├── .gitignore ├── src ├── icon.png ├── skin │ ├── LDAP.png │ ├── donate.png │ ├── icon.png │ ├── plus.png │ ├── advanced.png │ └── CC.license ├── content │ ├── qr-alipay.png │ ├── donate-with-alipay.png │ ├── donate-with-paypal.png │ ├── jquery-aop.txt │ ├── sprintf.LICENSE │ ├── defaults.js │ ├── ldapInfo.css │ ├── sprintf.jsm │ ├── ldapInfoLoadRemoteBase.jsm │ ├── log.jsm │ ├── aop.jsm │ ├── ldapInfoPrefDialog.xul │ ├── ldapInfoUtil.jsm │ ├── ldapInfoFetch.jsm │ └── ldapInfoFetchOther.jsm ├── chrome.manifest ├── release.sh ├── release.bat ├── locale │ └── en-US │ │ ├── ldapinfoshow.properties │ │ └── ldapinfoshow.dtd ├── install.rdf └── bootstrap.js ├── wiki_images ├── confirm.png ├── password.png ├── certificate.png ├── limitations.png └── certificate_warn.png ├── releases ├── ldapinfo-0.4-tb.xpi ├── ldapinfo-0.5-tb.xpi ├── ldapinfo-0.6-tb.xpi ├── ldapinfo-0.7-tb.xpi ├── ldapinfo-0.8-tb.xpi ├── ldapinfo-0.9-tb.xpi ├── ldapinfo-1.0-tb.xpi ├── ldapinfo-1.1-tb.xpi └── ldapinfo-1.2-tb.xpi ├── README.md ├── Help.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.xpi 2 | -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/icon.png -------------------------------------------------------------------------------- /src/skin/LDAP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/skin/LDAP.png -------------------------------------------------------------------------------- /src/skin/donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/skin/donate.png -------------------------------------------------------------------------------- /src/skin/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/skin/icon.png -------------------------------------------------------------------------------- /src/skin/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/skin/plus.png -------------------------------------------------------------------------------- /src/skin/advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/skin/advanced.png -------------------------------------------------------------------------------- /wiki_images/confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/wiki_images/confirm.png -------------------------------------------------------------------------------- /wiki_images/password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/wiki_images/password.png -------------------------------------------------------------------------------- /src/content/qr-alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/content/qr-alipay.png -------------------------------------------------------------------------------- /releases/ldapinfo-0.4-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.4-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-0.5-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.5-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-0.6-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.6-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-0.7-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.7-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-0.8-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.8-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-0.9-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-0.9-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-1.0-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-1.0-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-1.1-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-1.1-tb.xpi -------------------------------------------------------------------------------- /releases/ldapinfo-1.2-tb.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/releases/ldapinfo-1.2-tb.xpi -------------------------------------------------------------------------------- /wiki_images/certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/wiki_images/certificate.png -------------------------------------------------------------------------------- /wiki_images/limitations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/wiki_images/limitations.png -------------------------------------------------------------------------------- /src/content/donate-with-alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/content/donate-with-alipay.png -------------------------------------------------------------------------------- /src/content/donate-with-paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/src/content/donate-with-paypal.png -------------------------------------------------------------------------------- /wiki_images/certificate_warn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangvisual/ldapinfo/HEAD/wiki_images/certificate_warn.png -------------------------------------------------------------------------------- /src/chrome.manifest: -------------------------------------------------------------------------------- 1 | content ldapInfo content/ 2 | skin ldapInfo classic/1.0 skin/ 3 | locale ldapInfo en-US locale/en-US/ 4 | 5 | -------------------------------------------------------------------------------- /src/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | version=`sed -n -e "s/.*\(.*\)<\/em:version>/\1/p" install.rdf` 3 | zip -r ldapinfo-$version-tb.xpi * -x \*.git \*.xpi \*.sh \*.bat 4 | 5 | -------------------------------------------------------------------------------- /src/content/jquery-aop.txt: -------------------------------------------------------------------------------- 1 | jQuery AOP plugin v1.3 2 | http://jquery-aop.googlecode.com/ 3 | 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | -------------------------------------------------------------------------------- /src/skin/CC.license: -------------------------------------------------------------------------------- 1 | advanced.png are lincensed under: 2 | CC Attribution-No Derivative 4.0 3 | http://creativecommons.org/licenses/by-nd/4.0/ 4 | No changes were made to the icon 5 | Thanks to emey87 -------------------------------------------------------------------------------- /src/release.bat: -------------------------------------------------------------------------------- 1 | set PATH=c:\Program Files (x86)\7-Zip;c:\Program Files\7-Zip;d:\Program Files (x86)\7-Zip;d:\Program Files\7-Zip 2 | set zip=7z.exe a -tzip -mx1 -r 3 | set AllFiles=content locale skin defaults modules chrome.manifest icon.png install.rdf bootstrap.js 4 | del ldapinfo-*-tb.xpi 5 | %zip% ldapinfo-1.2-tb.xpi %AllFiles% -xr!.svn 6 | -------------------------------------------------------------------------------- /src/locale/en-US/ldapinfoshow.properties: -------------------------------------------------------------------------------- 1 | # 2013.11.11 2 | prompt.warning=Warning 3 | prompt.confirm.fbli=You've enabled load from Facebook\u00ae or LinkedIn\u00ae, As they only allow Microsoft\u00ae Outlook Social Connector to search, This addon mimic it's method and\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nUSE OF THIS FEATURE MAY CAUSE YOUR FACEBOOK/LINKEDIN ACCOUNT SUSPENDED OR DELETED, MAY LEAD TO FIRE HAZARD, EARTHQUAKE, TSUNAMI OR EVEN ALIEN TRESPASS. USE IT WITH CAUTIOUS. \n\nIf you lives in one of the S.I.C.K. countries like China, Please make sure you've setup method to bypass GFW in order to access Facebook\u00ae. 4 | prompt.confirm.bad.cert=%ADDON% need to connect to %SERVER%, however %APP% doesn't trust it, Please click OK and add permanent exception for it, click Cancel to disable %SERVICE%\u00ae support. 5 | prompt.noldap=Can't find any LDAP servers in address book, please setup one first or disable LDAP support! -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome ldapInfoShow 2 | 3 | Show contact photo and other info from Local Dir, Addressbook, LDAP, Flickr, Gravatar etc. 4 | 5 | This Add-on can read jpegPhoto and other entries from LDAP servers and then show it in mails pane, compose window and address book. 6 | 7 | It can helps you to know your colleagues and prevent sending email to wrong person. 8 | 9 | Requires a working LDAP server and config it in Thunderbird's Address Book. 10 | 11 | It use the same method as Outlook Social Connectors so you can have avatars from Facebook & LinkedIn users too. 12 | 13 | Check the [Help](https://github.com/wangvisual/ldapinfo/blob/master/Help.md) page for more. 14 | 15 | Add-ons created/maintained by me: 16 | * [Expression Search / GMailUI](https://addons.thunderbird.net/en-US/thunderbird/addon/gmailui/) Powerful message searching through expressions. Type "from:fred to:tom" to see all messages from Fred to Tom in the current view 17 | * [Awesome ldapInfoShow](https://addons.thunderbird.net/en-US/thunderbird/addon/ldapinfoshow/) Showing LDAP information 18 | * [Awesome Auto Archive](https://addons.thunderbird.net/en-US/thunderbird/addon/awesome-auto-archive/) Automatically do Archive/Copy/Delete/Move actions based on user defined rules 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/install.rdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ldapInfo@opera.wang 5 | 1.2 6 | 2 7 | true 8 | false 9 | 10 | 11 | Awesome ldapInfoShow 12 | Show contact photo and other info from Local Dir, Addressbook, LDAP, Intranet, Flickr, Gravatar etc 13 | Opera Wang 14 | 15 | chrome://ldapInfo/content/ldapInfoPrefDialog.xul 16 | https://github.com/wangvisual/ldapinfo 17 | 18 | 19 | 20 | 21 | {3550f703-e582-4d05-9a08-453d09bdfdc6} 22 | 60.0 23 | 63.0 24 | 25 | 26 | 27 | 28 | 29 | {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} 30 | 2.57 31 | 2.58 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/content/sprintf.LICENSE: -------------------------------------------------------------------------------- 1 | https://github.com/alexei/sprintf.js 2 | 3 | Copyright (c) 2007-2013, Alexandru Marasteanu 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of this software nor the names of its contributors may be 14 | used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Help.md: -------------------------------------------------------------------------------- 1 | # Introduction # 2 | Awesome ldapInfoShow is a Thunderbird addon that show contact photo and other info from LDAP for intranet, search avatar in social networks like Facebook, LinkedIn, Flickr, Google+, Gravatar from internet 3 | 4 | # LDAP Support # 5 | ldapInfoShow try to use the LDAP servers in Thunderbird's address book. If either of the Name/Hostname/Base DN contains the domain name of email address, then the LDAP server will be used for searching. 6 | 7 | If you believe the LDAP server should return someone but it errors out "no match", then you should play with the filter template in 'LDAP settings' for the addon. By default, it's: 8 | 9 | `(|(mail=%(email)s)(mailLocalAddress=%(email)s))` 10 | 11 | The filter will be `(|(mail=username@company.com)(mailLocalAddress=username@company.com)` for your searching, which means either the mail or mailLocalAddress should be username@company.com. 12 | 13 | For DavMail LDAP server, the filter should like `'(uid=%(uid)s)'`, and DavMail won't provide avatars. 14 | 15 | # LinkedIn Support ( NOT working any more )# 16 | 1. First need to enable it in Option, and click 'OK' for the warning confirmation. ![https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/confirm.png](https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/confirm.png) 17 | 1. Then It will ask for LinkedIn password through standard dialog. ![https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/password.png](https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/password.png) 18 | 1. At last You need to confirm and add the certificate used by LinkedIn to TB's exceptions. ![https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/certificate_warn.png](https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/certificate_warn.png) ![https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/certificate.png](https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/certificate.png) 19 | 20 | # Performance # 21 | 1. The more places you enabled, it take more time to load 22 | 1. Flickr/Gravar can only query 1 email at a time, and Flickr server is slow. 23 | 1. Facebook/LinkedIn/LDAP support batch query and it can save overall query time, but takes more time to load the 1st one. 24 | 1. Facebook/LinkedIn will query 25 emails at most in one query. 25 | 1. LDAP batch query limit is configurable in option dialog and only works when your query filter is simple, eg '(|(mail=%(email)s)(mailLocalAddress=%(email)s))' 26 | 1. You can also limit the total number of email addresses queried for one mail. 27 | ![https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/limitations.png](https://github.com/wangvisual/ldapinfo/blob/master/wiki_images/limitations.png) 28 | 29 | # Privacy # 30 | 1. The email addresses sent to Facebook/LinkedIn/Gravatar will be hashed first. 31 | 1. Flickr uses plain email address but transfer through https. 32 | 1. LDAP search uses plain email address. 33 | 1. Facebook/LinkedIn support are using Microsoft Outlook Connectors way of searching, so you will see the authorization to MOC in your Facebook/LinkedIn settings. 34 | 35 | # Future # 36 | 1. Support Twitter? If anyone can tell me how. 37 | 1. Xing? Maybe. 38 | 1. Support X-Face/Face header? No, they're obsolete. 39 | 40 | # Tips # 41 | 1. You can try to install addon that can sync your gmail contact to local address-book and config this addon to load avatar from it. 42 | -------------------------------------------------------------------------------- /src/content/defaults.js: -------------------------------------------------------------------------------- 1 | pref("extensions.ldapinfoshow.disabled_servers", ""); // "server1,server3" 2 | pref("extensions.ldapinfoshow.show_display_single_pics_at", 0); // 0: right, 1: left 3 | pref("extensions.ldapinfoshow.show_display_multi_pics_at", 0); 4 | pref("extensions.ldapinfoshow.show_compose_single_pics_at", 0); 5 | pref("extensions.ldapinfoshow.load_from_local_dir", false); 6 | pref("extensions.ldapinfoshow.load_from_domain_wildcard", false); 7 | pref("extensions.ldapinfoshow.local_pic_dir", ""); 8 | pref("extensions.ldapinfoshow.load_from_addressbook", true); 9 | pref("extensions.ldapinfoshow.load_from_ldap", true); 10 | pref("extensions.ldapinfoshow.ldap_batch", 36); // <= 1 will disable batch 11 | pref("extensions.ldapinfoshow.ldap_ignore_domain", false); 12 | pref("extensions.ldapinfoshow.load_from_intranet", true); 13 | pref("extensions.ldapinfoshow.load_from_general", true); 14 | pref("extensions.ldapinfoshow.load_from_facebook", false); 15 | pref("extensions.ldapinfoshow.facebook_token", ""); 16 | pref("extensions.ldapinfoshow.facebook_token_expire", "0"); 17 | pref("extensions.ldapinfoshow.ignore_facebook_default", true); 18 | pref("extensions.ldapinfoshow.load_from_linkedin", false); 19 | pref("extensions.ldapinfoshow.linkedin_user", ""); 20 | pref("extensions.ldapinfoshow.linkedin_token", ""); 21 | pref("extensions.ldapinfoshow.load_from_flickr", false); 22 | pref("extensions.ldapinfoshow.load_from_google", true); 23 | pref("extensions.ldapinfoshow.load_from_gravatar", true); 24 | pref("extensions.ldapinfoshow.ldap_attributes", 'cn,jpegPhoto,thumbnailPhoto,photo,telephoneNumber,pager,mobile,facsimileTelephoneNumber,mobileTelephoneNumber,pagerTelephoneNumber,physicalDeliveryOfficeName,ou,title,Reports,manager,employeeNumber,url'); 25 | pref("extensions.ldapinfoshow.filterTemplate", "(|(mail=%(email)s)(mailLocalAddress=%(email)s))"); 26 | pref("extensions.ldapinfoshow.load_from_photo_url", true); 27 | pref("extensions.ldapinfoshow.photoURL", "http://lookup/lookup/publicphotos/%(employeeNumber)08s.jpg"); 28 | pref("extensions.ldapinfoshow.click2dial", "http://lookup/lookup/click2dial/lookup-click2dial.cgi?dialstring=%s"); 29 | pref("extensions.ldapinfoshow.intranetTemplate", "http://mysp/User Photos/Profile Pictures/%(basic.mailCompany)s_%(ldap.uid)s_LThumb.jpg"); 30 | pref("extensions.ldapinfoshow.intranetProfileTemplate", 'http://mysp/Person.aspx?accountname=%(basic.mailCompany)s\\%(ldap.uid)s'); 31 | pref("extensions.ldapinfoshow.ldapTimeoutWhenCached", 20); 32 | pref("extensions.ldapinfoshow.ldapTimeoutInitial", 60); 33 | pref("extensions.ldapinfoshow.ldapIdleTimeout", 300); 34 | pref("extensions.ldapinfoshow.numberLimitSingle", 36); 35 | pref("extensions.ldapinfoshow.numberLimitMulti", 12); 36 | pref("extensions.ldapinfoshow.enable_verbose_info", false); 37 | pref("extensions.ldapinfoshow.warned_about_fbli", false); 38 | pref("extensions.ldapinfoshow.load_at_tc_header", true); 39 | pref("extensions.ldapinfoshow.only_check_author", false); 40 | pref("extensions.ldapinfoshow.general_icon_size", 0); // 0 is tiny, 1 is small 41 | pref("extensions.ldapinfoshow.add_margin_to_image", false); 42 | pref("extensions.ldapinfoshow.image_height_limit_tc_header", 32); 43 | pref("extensions.ldapinfoshow.image_height_limit_message_display_size_divide", 8); 44 | pref("extensions.ldapinfoshow.image_height_limit_message_display_many", 48); 45 | pref("extensions.ldapinfoshow.image_height_limit_message_display_few", 64); 46 | pref("extensions.ldapinfoshow.image_height_limit_compose", 128); 47 | pref("extensions.ldapinfoshow.image_height_limit_popup", 128); 48 | pref("extensions.ldapinfoshow.service_priority", 'local_dir>addressbook>ldap>intranet>facebook>linkedin>flickr>google>gravatar>domain_wildcard'); 49 | -------------------------------------------------------------------------------- /src/content/ldapInfo.css: -------------------------------------------------------------------------------- 1 | /* 2 | we enable on both xul and xhtml 3 | @namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); 4 | */ 5 | 6 | /* 7 | http://www.w3.org/TR/css3-conditional/ 8 | */ 9 | @-moz-document regexp("chrome://(messenger|ldapinfo|conversations)/content/.*") { 10 | 11 | #ldapinfo-statusbar-icon { 12 | list-style-image: url("chrome://ldapInfo/skin/icon.png"); 13 | } 14 | 15 | #ldapinfo-tooltip { 16 | margin: 0px; 17 | padding: 0px; 18 | border: 0px none !important; 19 | } 20 | 21 | #ldapinfo-tooltip > grid { 22 | } 23 | 24 | .ldapInfoPopupDetailColumn { 25 | max-width: 800px !important; 26 | } 27 | 28 | #ldapinfo-tooltip-rows > row:nth-child(odd) { 29 | background-color: #ffffe1 !important; 30 | } 31 | 32 | #ldapinfo-tooltip-rows > row:nth-child(even) { 33 | background-color: #ffffc0 !important; 34 | } 35 | 36 | #displayLDAPPhoto[orient="horizontal"] { 37 | flex: 1 1; 38 | -moz-box-flex: 1; 39 | overflow: auto; 40 | min-width: 300px; 41 | display: block; 42 | } 43 | 44 | #expandedHeaderView > #displayLDAPPhoto[orient="horizontal"] { /* when put left side for msg display window */ 45 | flex: 0 1; 46 | min-width: 100px; 47 | max-width: 600px; 48 | -moz-box-flex: 0; 49 | } 50 | 51 | #msgheaderstoolbar-box > #displayLDAPPhoto { /* when put left in compose window */ 52 | flex: 0 0; 53 | min-width: 128px; 54 | max-width: 128px; 55 | width: 128px; 56 | -moz-box-flex: 0; 57 | overflow: hidden; 58 | } 59 | 60 | /* https://bugzilla.mozilla.org/show_bug.cgi?id=702508, support since TB28 */ 61 | /*@supports (flex-wrap: wrap) { 62 | #displayLDAPPhoto[orient="horizontal"] { 63 | display: flex; 64 | flex-flow: row wrap; 65 | align-content: flex-end; 66 | justify-content: flex-start; 67 | } 68 | }*/ 69 | 70 | image.ldapInfoLoadingQueue, img.ldapInfoLoadingQueue, image.ldapInfoLoadingQueueOther, img.ldapInfoLoadingQueueOther { 71 | border: 1px dotted blue; 72 | } 73 | 74 | image.ldapInfoLoading, img.ldapInfoLoading, image.ldapInfoLoadingOther, img.ldapInfoLoadingOther { 75 | border: 1px dashed red; 76 | animation: ldapInfoAnimation 0.2s infinite alternate; 77 | } 78 | 79 | @keyframes ldapInfoAnimation { 80 | from { 81 | border-color: red; 82 | } 83 | to { 84 | border-color: green; 85 | } 86 | } 87 | 88 | image.ldapInfoMoreInfo { 89 | border-width: 2px; 90 | border-color: green; 91 | border-bottom-style: dashed; 92 | } 93 | 94 | image.ldapInfoMoreInfo[MultiSrc="true"] { 95 | border-width: 2px; 96 | border-color: red; 97 | border-bottom-style: dashed; 98 | } 99 | 100 | #displayLDAPPhoto .ldapInfoInnerBox { 101 | position: relative; 102 | flex: 0 0 auto; 103 | } 104 | 105 | #displayLDAPPhoto .ldapInfoInnerBoxWithMargin { 106 | margin: 4px 4px 0 4px !important; 107 | } 108 | 109 | #displayLDAPPhoto div { 110 | display: none; 111 | } 112 | 113 | #displayLDAPPhoto div.ldapInfoMoreInfo { 114 | width: 8px; 115 | height: 8px; 116 | display: block; 117 | position: absolute; 118 | bottom: 0px; 119 | left: 0px; 120 | background: url(chrome://ldapInfo/skin/plus.png) no-repeat; 121 | transform: rotate(45deg); 122 | } 123 | 124 | #displayLDAPPhoto div.ldapInfoMoreInfo[MultiSrc="true"] { 125 | transform: rotate(0deg); 126 | } 127 | 128 | #ldapinfoshow-perfpane { 129 | overflow: auto; 130 | min-width: 600px; 131 | } 132 | 133 | #ldapinfoshow-perfpane textbox[readonly="true"] { 134 | color: grey !important; 135 | } 136 | 137 | #ldapinfoshow-perfpane checkbox.ldapinfoshow-enable-checked:not([checked]) + hbox, 138 | #ldapinfoshow-perfpane checkbox.ldapinfoshow-enable-checked:not([checked]) + hbox textbox { 139 | color: grey !important; 140 | } 141 | 142 | #ldapinfoshow-perfpane .ldapinfoshow-center-rows row{ 143 | box-align: center; 144 | -moz-box-align: center; 145 | } 146 | 147 | #ldapinfoshow-select-icon-size *{ 148 | max-height: 64px; 149 | } 150 | 151 | } -------------------------------------------------------------------------------- /src/locale/en-US/ldapinfoshow.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | '"> 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/bootstrap.js: -------------------------------------------------------------------------------- 1 | // Opera.Wang+ldapInfo@gmail.com GPL/MPL 2 | "use strict"; 3 | 4 | const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, results: Cr, manager: Cm } = Components; 5 | Cu.import("resource://gre/modules/Services.jsm"); 6 | // if use custom resouce, refer here 7 | // http://mdn.beonex.com/en/JavaScript_code_modules/Using.html 8 | 9 | const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); 10 | const userCSS = Services.io.newURI("chrome://ldapInfo/content/ldapInfo.css", null, null); 11 | const targetWindows = [ "mail:3pane", "msgcompose", "mail:addressbook", "mail:messageWindow" ]; 12 | const targetLocations = [ "chrome://messenger/content/addressbook/abEditCardDialog.xul" ]; 13 | 14 | function loadIntoWindow(window) { 15 | if ( !window ) return; // windows is the global host context 16 | let document = window.document; // XULDocument 17 | let type = document.documentElement.getAttribute('windowtype'); // documentElement maybe 'messengerWindow' / 'addressbookWindow' 18 | if ( targetWindows.indexOf(type) < 0 && targetLocations.indexOf(window.location.href) < 0 ) return; 19 | ldapInfo.Load(window); 20 | } 21 | 22 | var windowListener = { 23 | onOpenWindow: function(aWindow) { 24 | let onLoadWindow = function() { 25 | aWindow.removeEventListener("load", onLoadWindow, false); 26 | let msgComposeWindow = aWindow.document.getElementById("msgcomposeWindow"); 27 | if ( msgComposeWindow ) msgComposeWindow.removeEventListener("compose-window-reopen", onLoadWindow, false); 28 | loadIntoWindow(aWindow); 29 | }; 30 | aWindow.addEventListener("load", onLoadWindow, false); 31 | let msgComposeWindow = aWindow.document.getElementById("msgcomposeWindow"); 32 | if ( msgComposeWindow ) { 33 | if ( aWindow.ComposeFieldsReady ) loadIntoWindow(aWindow); // compose-window-reopen won't work for TB24 2013.06.10? 34 | msgComposeWindow.addEventListener("compose-window-reopen", onLoadWindow, false); 35 | } 36 | }, 37 | //onCloseWindow: function(aWindow) {}, onWindowTitleChange: function(aWindow) {}, 38 | observe: function(subject, topic, data) { 39 | if ( topic == "xul-window-registered") { 40 | windowListener.onOpenWindow( subject.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow) ); 41 | } 42 | }, 43 | }; 44 | 45 | // A toplevel window in a XUL app is an nsXULWindow. Inside that there is an nsGlobalWindow (aka nsIDOMWindow). 46 | function startup(aData, aReason) { 47 | Services.console.logStringMessage("Awesome ldapInfoShow startup..."); 48 | Cu.import("chrome://ldapInfo/content/ldapInfoUtil.jsm"); 49 | ldapInfoUtil.initPerf(); 50 | Cu.import("chrome://ldapInfo/content/ldapInfo.jsm"); 51 | ldapInfoUtil.setChangeCallback( function(clean) { ldapInfo.clearCache(clean); } ); 52 | // Load into any existing windows, but not hidden/cached compose window, until compose window recycling is disabled by bug https://bugzilla.mozilla.org/show_bug.cgi?id=777732 53 | let windows = Services.wm.getEnumerator(null); 54 | while (windows.hasMoreElements()) { 55 | let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); 56 | if ( domWindow.document.readyState == "complete" 57 | && ( targetWindows.indexOf(domWindow.document.documentElement.getAttribute('windowtype')) >= 0 || targetLocations.indexOf(domWindow.location.href) >= 0 ) ) { 58 | loadIntoWindow(domWindow); 59 | } else { 60 | windowListener.onOpenWindow(domWindow); 61 | } 62 | } 63 | // Wait for new windows 64 | //Services.ww.registerNotification(windowListener); // nsIDOMWindow, can't get cached compose window open call 65 | //Services.wm.addListener(windowListener); // nsIXULWindow, onOpenWindow, onCloseWindow, onWindowTitleChange, works with compose window 66 | Services.obs.addObserver(windowListener, "xul-window-registered", false); 67 | //Services.obs.addObserver(windowListener, "domwindowopened", false); 68 | // install userCSS, works for all document like userChrome.css, see https://developer.mozilla.org/en/docs/Using_the_Stylesheet_Service 69 | // validator warnings on the below line, ignore it 70 | if ( !sss.sheetRegistered(userCSS, sss.USER_SHEET) ) sss.loadAndRegisterSheet(userCSS, sss.USER_SHEET); // will be unregister when shutdown 71 | } 72 | 73 | function shutdown(aData, aReason) { 74 | // When the application is shutting down we normally don't have to clean up any UI changes made 75 | // but we have to abort LDAP related job or crash 76 | try { 77 | if ( sss.sheetRegistered(userCSS, sss.USER_SHEET) ) sss.unregisterSheet(userCSS, sss.USER_SHEET); 78 | } catch (err) {Cu.reportError(err);} 79 | 80 | try { 81 | //Services.ww.unregisterNotification(windowListener); 82 | Services.obs.removeObserver(windowListener, "xul-window-registered"); 83 | // Unload from any existing windows 84 | let windows = Services.wm.getEnumerator(null); 85 | while (windows.hasMoreElements()) { 86 | let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); 87 | ldapInfo.unLoad(domWindow); // won't check windowtype as unload will check 88 | // Do CC & GC, comment out allTraces when release 89 | domWindow.windowUtils.garbageCollect( 90 | // Cc["@mozilla.org/cycle-collector-logger;1"].createInstance(Ci.nsICycleCollectorListener).allTraces() 91 | ); 92 | } 93 | ldapInfo.cleanup(); // it's will abort ldap queries so should before the next line 94 | } catch (err) {Cu.reportError(err);} 95 | if (aReason == APP_SHUTDOWN) return; 96 | Services.strings.flushBundles(); // clear string bundles 97 | ["aop", "sprintf", "ldapInfoFetch", "ldapInfoFetchOther", "ldapInfo", "ldapInfoUtil", "ldapInfoLoadRemoteBase", "log"].forEach( function(file) { 98 | Cu.unload("chrome://ldapInfo/content/" + file + ".jsm"); 99 | } ); 100 | try { 101 | ldapInfo = ldapInfoUtil = null; 102 | } catch (err) {Cu.reportError(err);} 103 | // flushStartupCache 104 | // Init this, so it will get the notification. 105 | //Cc["@mozilla.org/xul/xul-prototype-cache;1"].getService(Ci.nsISupports); 106 | Services.obs.notifyObservers(null, "startupcache-invalidate", null); 107 | Cu.schedulePreciseGC( Cu.forceGC ); 108 | Services.console.logStringMessage("Awesome ldapInfoShow shutdown"); 109 | } 110 | 111 | function install(aData, aReason) {} 112 | function uninstall(aData, aReason) {} 113 | -------------------------------------------------------------------------------- /src/content/sprintf.jsm: -------------------------------------------------------------------------------- 1 | /*! sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu | 3 clause BSD license */ 2 | "use strict"; 3 | var EXPORTED_SYMBOLS = ["ldapInfoSprintf"]; 4 | Components.utils.import("resource://gre/modules/Services.jsm"); 5 | let ldapInfoSprintf = {}; 6 | let exports = ldapInfoSprintf; 7 | (function (ctx) { 8 | let sprintf = function () { 9 | if (!sprintf.cache.hasOwnProperty(arguments[0])) { 10 | sprintf.cache[arguments[0]] = sprintf.parse(arguments[0]); 11 | } 12 | return sprintf.format.call(null, sprintf.cache[arguments[0]], arguments); 13 | }; 14 | sprintf.format = function (parse_tree, argv) { 15 | var cursor = 1, 16 | tree_length = parse_tree.length, 17 | node_type = '', 18 | arg, output = [], 19 | i, k, match, pad, pad_character, pad_length; 20 | for (i = 0; i < tree_length; i++) { 21 | node_type = get_type(parse_tree[i]); 22 | if (node_type === 'string') { 23 | output.push(parse_tree[i]); 24 | } else if (node_type === 'array') { 25 | match = parse_tree[i]; // convenience purposes only 26 | if (match[2]) { // keyword argument 27 | arg = argv[cursor]; 28 | for (k = 0; k < match[2].length; k++) { 29 | if (!arg.hasOwnProperty(match[2][k])) { 30 | throw (sprintf('[sprintf] property "%s" does not exist', match[2][k])); 31 | } 32 | arg = arg[match[2][k]]; 33 | } 34 | } else if (match[1]) { // positional argument (explicit) 35 | arg = argv[match[1]]; 36 | } else { // positional argument (implicit) 37 | arg = argv[cursor++]; 38 | } 39 | if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { 40 | throw (sprintf('[sprintf] expecting number but found %s', get_type(arg))); 41 | } 42 | switch (match[8]) { 43 | case 'b': 44 | arg = arg.toString(2); 45 | break; 46 | case 'c': 47 | arg = String.fromCharCode(arg); 48 | break; 49 | case 'd': 50 | arg = parseInt(arg, 10); 51 | break; 52 | case 'e': 53 | arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); 54 | break; 55 | case 'f': 56 | arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); 57 | break; 58 | case 'o': 59 | arg = arg.toString(8); 60 | break; 61 | case 's': 62 | arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); 63 | break; 64 | case 'u': 65 | arg = arg >>> 0; 66 | break; 67 | case 'x': 68 | arg = arg.toString(16); 69 | break; 70 | case 'X': 71 | arg = arg.toString(16).toUpperCase(); 72 | break; 73 | } 74 | arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+' + arg : arg); 75 | pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; 76 | pad_length = match[6] - String(arg).length; 77 | pad = match[6] ? str_repeat(pad_character, pad_length) : ''; 78 | output.push(match[5] ? arg + pad : pad + arg); 79 | } 80 | } 81 | // Services.console.logStringMessage(output.join(',')); 82 | return output.join(''); 83 | }; 84 | sprintf.cache = {}; 85 | sprintf.parse = function (fmt) { 86 | var _fmt = fmt, 87 | match = [], 88 | parse_tree = [], 89 | arg_names = 0; 90 | while (_fmt) { 91 | if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { 92 | parse_tree.push(match[0]); 93 | } else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { 94 | parse_tree.push('%'); 95 | } else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { 96 | if (match[2]) { 97 | arg_names |= 1; 98 | var field_list = [], 99 | replacement_field = match[2], 100 | field_match = []; 101 | if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { 102 | field_list.push(field_match[1]); 103 | while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { 104 | if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { 105 | field_list.push(field_match[1]); 106 | } else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { 107 | field_list.push(field_match[1]); 108 | } else { 109 | throw ('[sprintf] huh?'); 110 | } 111 | } 112 | } else { 113 | throw ('[sprintf] huh?'); 114 | } 115 | match[2] = field_list; 116 | } else { 117 | arg_names |= 2; 118 | } 119 | if (arg_names === 3) { 120 | throw ('[sprintf] mixing positional and named placeholders is not (yet) supported'); 121 | } 122 | parse_tree.push(match); 123 | } else { 124 | throw ('[sprintf] huh?'); 125 | } 126 | _fmt = _fmt.substring(match[0].length); 127 | } 128 | return parse_tree; 129 | }; 130 | var vsprintf = function (fmt, argv, _argv) { 131 | _argv = argv.slice(0); 132 | _argv.splice(0, 0, fmt); 133 | return sprintf.apply(null, _argv); 134 | }; 135 | /** 136 | * helpers 137 | */ 138 | 139 | function get_type(variable) { 140 | return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); 141 | } 142 | 143 | function str_repeat(input, multiplier) { 144 | for (var output = []; multiplier > 0; output[--multiplier] = input) { /* do nothing */ } 145 | return output.join(''); 146 | } 147 | /** 148 | * export to either browser or node.js 149 | */ 150 | ctx.sprintf = sprintf; 151 | ctx.vsprintf = vsprintf; 152 | })(typeof exports != "undefined" ? exports : {}); -------------------------------------------------------------------------------- /src/content/ldapInfoLoadRemoteBase.jsm: -------------------------------------------------------------------------------- 1 | // license: GPL V3 2 | 3 | "use strict"; 4 | var EXPORTED_SYMBOLS = ["ldapInfoLoadRemoteBase"]; 5 | const { results: Cr } = Components; 6 | Cu.importGlobalProperties(["XMLHttpRequest"]); 7 | Cu.import("resource://gre/modules/Services.jsm"); 8 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 9 | Cu.import("chrome://ldapInfo/content/log.jsm"); 10 | Cu.import("chrome://ldapInfo/content/sprintf.jsm"); 11 | Cu.import("chrome://ldapInfo/content/ldapInfoUtil.jsm"); 12 | 13 | function ldapInfoLoadRemoteBase(callbackData, name, target, url, loadNextRemote) { 14 | let self = this; // new Object 15 | self.callbackData = callbackData; 16 | self.name = name; 17 | self.target = target; 18 | self.url = url; 19 | self.loadNextRemote = loadNextRemote; 20 | self.isSuccess = function(request) { return true; }; 21 | self.addtionalErrMsg = ""; 22 | self.badCert = false; 23 | self.WhenError = function(request, type, retry) {}; 24 | self.method = "GET"; 25 | self.type = 'arraybuffer'; 26 | self.isChained = false; // for FacebookFQLSearch etc, when success, will chain another request 27 | self.data = null; 28 | return this; 29 | } 30 | 31 | ldapInfoLoadRemoteBase.prototype = { 32 | // modify from old AddonManager.jsm 33 | // https://wiki.mozilla.org/User:Dolske/PromptRework 34 | QueryInterface: ChromeUtils.generateQI ? ChromeUtils.generateQI([Ci.nsIInterfaceRequestor]) : XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]), 35 | getInterface: function(iid) { 36 | let win = this.callbackData.win.get(); 37 | if ( iid.equals(Ci.nsIAuthPrompt2) ) { 38 | return Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].getService(Ci.nsIPromptFactory).getPrompt(win, Ci.nsIAuthPrompt2); 39 | } 40 | throw Cr.NS_ERROR_NO_INTERFACE; 41 | }, 42 | WhenSuccess: function(request) { 43 | if ( this.target == 'google' ) this.callbackData.cache.google['Google Profile'] = ["https://profiles.google.com/" + this.callbackData.mailid]; 44 | if ( this.target == 'gravatar' ) this.callbackData.cache.gravatar['Gravatar Profile'] = ["https://secure.gravatar.com/" + this.callbackData.gravatarHash]; 45 | try { 46 | if ( this.target == 'intranet' ) this.callbackData.cache.intranet['Intranet Profile'] = [ldapInfoSprintf.sprintf( ldapInfoUtil.options.intranetProfileTemplate, { basic: this.callbackData, ldap: this.callbackData.cache.ldap } )]; 47 | } catch(err) {} 48 | let type = request.getResponseHeader('Content-Type') || 'image/png'; // image/gif or application/json; charset=utf-8 or text/html; charset=utf-8 49 | let win = this.callbackData.win.get(); 50 | if ( win && win.btoa && type != 'text/xml' && request.response ) { 51 | this.callbackData.cache[this.target].src = "data:" + type + ";base64," + ldapInfoUtil.byteArray2Base64(win, request.response); 52 | } 53 | }, 54 | setRequestHeader: function(request) { }, 55 | beforeRequest: function() { return true; }, 56 | AfterSuccess: function(has_user) { // change state/_Status, call loadNextRemote if needed 57 | if ( !this.isChained ) { 58 | this.callbackData.cache[this.target].state = ldapInfoUtil.STATE_DONE; 59 | this.callbackData.cache[this.target]._Status = [this.name + ' ' 60 | + ( this.callbackData.cache[this.target].src ? ldapInfoUtil.CHAR_HAVEPIC : ( typeof(has_user) != 'undefined' ? ldapInfoUtil.CHAR_NOPIC : ldapInfoUtil.CHAR_NOUSER ) )]; 61 | } 62 | this.loadNextRemote(this.callbackData); 63 | }, 64 | makeRequest: function() { 65 | let self = this; 66 | if ( !self.beforeRequest() ) return; 67 | let callbackData = self.callbackData; 68 | ldapInfoLog.info(self.method + " URL " + self.url); 69 | // Using XMLHttpRequest from hiddenDOMWindow create several problems 70 | // It will show 'Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ...', can bypass using mozSystem 71 | // But it can't show password prompt because 'Cannot call openModalWindow on a hidden window' 72 | // let XMLHttpRequest = Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci.nsIAppShellService).hiddenDOMWindow.XMLHttpRequest; 73 | // let oReq = new XMLHttpRequest(); 74 | // this not work either: 75 | // let win = callbackData.win.get(); 76 | // let oReq = new win.XMLHttpRequest({mozSystem: true}); // the same origin policy will not be enforced on the request 77 | // https://developer.mozilla.org/en-US/docs/nsIXMLHttpRequest 78 | // let oReq = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); // > TB15 79 | // https://bugzilla.mozilla.org/show_bug.cgi?id=792808 Gut nsIXMLHttpRequest 80 | let oReq = new XMLHttpRequest(); // > TB28? 81 | oReq.open(self.method, self.url, true); 82 | oReq.responseType = self.type; 83 | oReq.timeout = ldapInfoUtil.options['ldapTimeoutInitial'] * 1000; 84 | oReq.withCredentials = true; 85 | oReq.mozBackgroundRequest = false; 86 | let loadListener = function(event) { 87 | let request = event.target || this; 88 | delete callbackData.req; 89 | let success = ( event.type == 'load' && request.status == "200" && request.response ) && self.isSuccess(request); 90 | ldapInfoLog.info('XMLHttpRequest of ' + self.name + ' for ' + callbackData.address + " " + event.type + " status:" + request.status + " success:" + success); 91 | if ( success ) { 92 | self.WhenSuccess(request); 93 | self.AfterSuccess(true); 94 | } else { 95 | if ( event.type != 'load' ) { // error happens 96 | callbackData.cache[self.target].state = ldapInfoUtil.STATE_TEMP_ERROR; 97 | let status = request.channel.QueryInterface(Ci.nsIRequest).status; 98 | ldapInfoLog.info("nsIRequest status 0x" + status.toString(16) + " :" + ldapInfoUtil.getErrorMsg(status)); 99 | if ( event.type == 'timeout' || event.type == 'abort' ) { 100 | self.addtionalErrMsg += ' ' + event.type; 101 | if ( event.type == 'timeout' ) ldapInfoLog.log("Query for " + self.name + " meet time out " + (request.timeout/1000) + " S", "Timeout"); 102 | } else { // 'error' 103 | if ((status & 0xff0000) === 0x5a0000) { // Security module 104 | self.addtionalErrMsg += ' Security Error'; 105 | self.badCert = true; 106 | } else { 107 | self.addtionalErrMsg += ' ' + ldapInfoUtil.getErrorMsg(status).replace(/^NS_ERROR_/, ''); 108 | } 109 | } 110 | } 111 | if ( [0, 200, 403].indexOf(request.status) >= 0 && self.type != 'document' ) ldapInfoLog.logObject(request.response,'request.response ' + request.responseType,1); 112 | if ( callbackData.cache[self.target].state < ldapInfoUtil.STATE_DONE ) callbackData.cache[self.target].state = ldapInfoUtil.STATE_DONE; 113 | if ( request.status != 404 ) { 114 | if ( request.response && request.response.error_msg ) { 115 | self.addtionalErrMsg += " " + request.response.error_msg; 116 | } else if ( request.status != 200 && request.statusText ) self.addtionalErrMsg += " " + request.statusText; 117 | } 118 | let retry = false; 119 | if (self.badCert) { 120 | let win = callbackData.win.get(); 121 | if ( win && win.document ) { 122 | let url = Services.io.newURI(self.url, null, null); 123 | let strBundle = Services.strings.createBundle('chrome://ldapInfo/locale/ldapinfoshow.properties'); 124 | let msg = strBundle.GetStringFromName("prompt.confirm.bad.cert").replace('%SERVER%', url.prePath).replace('%SERVICE%', self.name).replace('%ADDON%', ldapInfoUtil.Name).replace('%APP%', Services.appinfo.name); 125 | let result = Services.prompt.confirm(win, strBundle.GetStringFromName("prompt.warning"), msg); 126 | let args = {location: url.prePath, prefetchCert: true}; 127 | if ( result ) win.openDialog("chrome://pippki/content/exceptionDialog.xul", "Opt", "chrome,dialog,modal", args); 128 | retry = result && args.exceptionAdded; 129 | if ( !retry ) { 130 | ldapInfoLog.log("Disable ' + self.name + ' support.", 1); 131 | ldapInfoUtil.prefs.setBoolPref('load_from_' + self.target, false); 132 | } 133 | } 134 | } 135 | self.WhenError(request, event.type, retry); 136 | callbackData.cache[self.target]._Status = [self.name + self.addtionalErrMsg + " " + ldapInfoUtil.CHAR_NOUSER]; 137 | self.loadNextRemote(callbackData); 138 | } 139 | request.removeEventListener("load", loadListener, false); 140 | request.removeEventListener("abort", loadListener, false); 141 | request.removeEventListener("error", loadListener, false); 142 | request.removeEventListener("timeout", loadListener, false); 143 | request.abort(); // without abort, when disable add-on, it takes quite a while to unload this js module 144 | }; 145 | oReq.addEventListener("load", loadListener, false); 146 | oReq.addEventListener("abort", loadListener, false); 147 | oReq.addEventListener("error", loadListener, false); 148 | oReq.addEventListener("timeout", loadListener, false); 149 | //oReq.addEventListener("loadend", loadListener, false); // loadend including load/error/abort/timeout 150 | //oReq.open(self.method, self.url, true); // on TB31, put here will cause error 'An attempt was made to use an object that is not, or is no longer, usable' for "oReq.responseType = self.type;" 151 | callbackData.req = oReq; // only the latest request will be saved for later possible abort 152 | self.setRequestHeader(oReq); 153 | oReq.channel.notificationCallbacks = self; // so prompt can save password 154 | oReq.send(self.data); 155 | }, 156 | }; 157 | -------------------------------------------------------------------------------- /src/content/log.jsm: -------------------------------------------------------------------------------- 1 | // Opera Wang, 2010/1/15 2 | // GPL V3 / MPL 3 | // debug utils 4 | "use strict"; 5 | const { stack: Cs } = Components; 6 | const { loader, require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); 7 | Cu.import("resource://gre/modules/Services.jsm"); 8 | Cu.import("resource:///modules/iteratorUtils.jsm"); // import toXPCOMArray 9 | 10 | // Console.jsm in Gecko < 23 calls dump(), not to Error Console 11 | const {console} = Cu.import("resource://gre/modules/Console.jsm", {}); 12 | 13 | // for Error Console in Gecko > 44 14 | let {HUDService} = require("devtools/client/webconsole/hudservice"); 15 | 16 | const popupImage = "chrome://messenger/skin/addressbook/icons/contact-generic.png"; 17 | var EXPORTED_SYMBOLS = ["ldapInfoLog"]; 18 | let ldapInfoLog = { 19 | popupDelay: null, 20 | setPopupDelay: function(delay) { 21 | this.popupDelay = delay * 1000; // input unit is seconds, internal using ms 22 | }, 23 | popupListener: { 24 | observe: function(subject, topic, cookie) { 25 | if ( topic == 'alertclickcallback' ) { // or alertfinished / alertshow(Gecko22) 26 | HUDService.openBrowserConsoleOrFocus(); 27 | } else if ( topic == 'alertfinished' ) { 28 | delete popupWins[cookie]; 29 | } 30 | } 31 | }, 32 | popup: function(title, msg) { 33 | if ( this.popupDelay == null ) { 34 | try { 35 | // alerts.totalOpenTime was removed on OS X @ TB 52: https://bugzilla.mozilla.org/show_bug.cgi?id=1290324 36 | // default value for getIntPerf was added @ TB54 37 | this.popupDelay = Services.prefs.getIntPref("alerts.totalOpenTime", 4000); // TB default is 10s, our default is 4s 38 | } catch (e) { 39 | this.popupDelay = 4000; 40 | } 41 | } 42 | let delay = this.popupDelay / 1000; // chaning ms to seconds 43 | if ( delay <= 0 ) return; 44 | /* 45 | http://mdn.beonex.com/en/Working_with_windows_in_chrome_code.html 46 | https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIAlertsService 47 | https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Alerts_and_Notifications 48 | Before Gecko 22, alert-service won't work with bb4win, use xul instead 49 | https://bugzilla.mozilla.org/show_bug.cgi?id=782211 50 | From Gecko 22, nsIAlertsService also use XUL on all platforms and easy to pass args, but difficult to get windows, so hard to change display time 51 | let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); 52 | alertsService.showAlertNotification(popupImage, title, msg, true, cookie, this.popupListener, name); 53 | */ 54 | let cookie = Date.now(); 55 | // arguments[0] --> the image src url 56 | // arguments[1] --> the alert title 57 | // arguments[2] --> the alert text 58 | // arguments[3] --> is the text clickable? 59 | // arguments[4] --> the alert cookie to be passed back to the listener 60 | // arguments[5] --> the alert origin reported by the look and feel 61 | // arguments[6] --> bidi 62 | // arguments[7] --> lang 63 | // arguments[8] --> requires interaction 64 | // arguments[9] --> replaced alert window (nsIDOMWindow) 65 | // arguments[10] --> an optional callback listener (nsIObserver) 66 | // arguments[11] -> the nsIURI.hostPort of the origin, optional 67 | // arguments[12] -> the alert icon URL, optional 68 | let args = [popupImage, title, msg, true, cookie, 0, '', '', null, false, this.popupListener]; 69 | // win is nsIDOMJSWindow, nsIDOMWindow 70 | let win = Services.ww.openWindow(null, 'chrome://global/content/alerts/alert.xul', "_blank", 'chrome,titlebar=no,popup=yes', 71 | // https://alexvincent.us/blog/?p=451 72 | // https://groups.google.com/forum/#!topic/mozilla.dev.tech.js-engine/NLDZFQJV1dU 73 | toXPCOMArray(args.map( function(arg) { 74 | let variant = Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIWritableVariant); 75 | if ( arg && typeof(arg) == 'object' ) variant.setAsInterface(Ci.nsIObserver, arg); // to pass the listener interface 76 | else variant.setFromVariant(arg); 77 | return variant; 78 | } ), Ci.nsIMutableArray)); 79 | popupWins[cookie] = Cu.getWeakReference(win); 80 | // sometimes it's too late to set win.arguments here when the xul window is reused. 81 | // win.arguments = args; 82 | let popupLoad = function() { 83 | win.removeEventListener('load', popupLoad, false); 84 | if ( win.document ) { 85 | let alertBox = win.document.getElementById('alertBox'); 86 | if ( alertBox ) alertBox.style.animationDuration = delay + "s"; 87 | let text = win.document.getElementById('alertTextLabel'); 88 | if ( text && win.arguments[3] ) text.classList.add('awsome_auto_archive-popup-clickable'); 89 | } 90 | win.moveWindowToEnd = function() { // work around https://bugzilla.mozilla.org/show_bug.cgi?id=324570, Make simultaneous notifications from alerts service work 91 | let x = win.screen.availLeft + win.screen.availWidth - win.outerWidth; 92 | let y = win.screen.availTop + win.screen.availHeight - win.outerHeight; 93 | let windows = Services.wm.getEnumerator('alert:alert'); 94 | while (windows.hasMoreElements()) { 95 | let alertWindow = windows.getNext(); 96 | if (alertWindow != win && alertWindow.screenY > win.outerHeight) y = Math.min(y, alertWindow.screenY - win.outerHeight); 97 | } 98 | let WINDOW_MARGIN = 10; y += -WINDOW_MARGIN; x += -WINDOW_MARGIN; 99 | win.moveTo(x, y); 100 | } 101 | }; 102 | if ( win.document.readyState == "complete" ) popupLoad(); 103 | else win.addEventListener('load', popupLoad, false); 104 | }, 105 | cleanup: function() { 106 | try { 107 | this.info("Log cleanup"); 108 | for ( let cookie in popupWins ) { 109 | let newwin = popupWins[cookie].get(); 110 | this.info("close alert window:" + cookie); 111 | if ( newwin && newwin.document && !newwin.closed ) newwin.close(); 112 | }; 113 | popupWins = {}; 114 | this.info("Log cleanup done"); 115 | } catch(err){} 116 | }, 117 | 118 | now: function() { //author: meizz 119 | let format = "yyyy-MM-dd hh:mm:ss.SSS "; 120 | let time = new Date(); 121 | let o = { 122 | "M+" : time.getMonth()+1, //month 123 | "d+" : time.getDate(), //day 124 | "h+" : time.getHours(), //hour 125 | "m+" : time.getMinutes(), //minute 126 | "s+" : time.getSeconds(), //second 127 | "q+" : Math.floor((time.getMonth()+3)/3), //quarter 128 | "S+" : time.getMilliseconds() //millisecond 129 | } 130 | 131 | if(/(y+)/.test(format)) format=format.replace(RegExp.$1, 132 | (time.getFullYear()+"").substr(4 - RegExp.$1.length)); 133 | for(let k in o)if(new RegExp("("+ k +")").test(format)) 134 | format = format.replace(RegExp.$1, 135 | RegExp.$1.length==1 ? o[k] : 136 | ("000"+ o[k]).substr((""+ o[k]).length+3-RegExp.$1.length)); 137 | return format; 138 | }, 139 | 140 | verbose: false, 141 | setVerbose: function(verbose) { 142 | this.verbose = verbose; 143 | }, 144 | 145 | info: function(msg, popup, force) { 146 | if (!force && !this.verbose) return; 147 | this.log(this.now() + msg, popup, true); 148 | }, 149 | 150 | log: function(msg, popup, info) { 151 | // https://developer.mozilla.org/en-US/docs/Tools/Web_Console/Custom_output 152 | if ( ( typeof(info) != 'undefined' && info ) || !Components || !Cs || !Cs.caller ) { 153 | Services.console.logStringMessage(msg); 154 | } else { 155 | let scriptError = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError); 156 | scriptError.init(msg, Cs.caller.filename, Cs.caller.sourceLine, Cs.caller.lineNumber, 0, scriptError.warningFlag, "chrome javascript"); 157 | Services.console.logMessage(scriptError); 158 | } 159 | if (popup) { 160 | if ( typeof(popup) != 'string' ) popup = 'Warning!'; 161 | this.popup(popup,msg); 162 | } 163 | }, 164 | 165 | // from errorUtils.js 166 | dumpValue: function(value, i, recurse, compress, pfx, tee, level, map) { 167 | let t = "", s= ""; 168 | try { t = typeof(value); } 169 | catch (err) { s += pfx + tee + " (exception) " + err + "\n"; } 170 | switch (t) { 171 | case "function": 172 | let sfunc = String(value).split("\n"); 173 | if ( String(value).match(/^\s+\[native code\]$/m) ) 174 | sfunc = "[native code]"; 175 | else 176 | sfunc = sfunc.length + " lines"; 177 | s += pfx + tee + i + " (function) " + map + sfunc + "\n"; 178 | break; 179 | case "object": 180 | s += pfx + tee + i + " (object) " + map + value + "\n"; 181 | if (!compress) 182 | s += pfx + "|\n"; 183 | if ((i != "parent") && (recurse) && value != null) 184 | s += this.objectTreeAsString(value, recurse - 1, compress, level + 1); 185 | break; 186 | case "string": 187 | if (value.length > 8192 + 5) 188 | s += pfx + tee + i + " (" + t + ")" + map + "'" + value.substr(0, 8192) + "' ... (" + value.length + " chars)\n"; 189 | else 190 | s += pfx + tee + i + " (" + t + ")" + map + "'" + value + "'\n"; 191 | break; 192 | case "": 193 | break; 194 | default: 195 | s += pfx + tee + i + " (" + t + ") " + map + value + "\n"; 196 | } 197 | if (!compress) s += pfx + "|\n"; 198 | return s; 199 | }, 200 | ignoreArray: new Array(), 201 | ignoreMap: new Map(), 202 | ignoreString: new String(), 203 | objectTreeAsString: function(o, recurse, compress, level) { 204 | let s = ""; 205 | let pfx = ""; 206 | let tee = ""; 207 | try { 208 | if (recurse === undefined) recurse = 0; 209 | if (level === undefined) level = 0; 210 | if (compress === undefined) compress = true; 211 | 212 | for (let junk = 0; junk < level; junk++) 213 | pfx += (compress) ? "| " : "| "; 214 | tee = (compress) ? "+ " : "+- "; 215 | if ( typeof(o) != 'undefined' && o != null ) { 216 | let index = this._checked.indexOf(o); 217 | if ( index >= 0 ) return pfx + tee + '[already shown]\n'; 218 | else this._checked.push(o); 219 | } 220 | if (typeof(o) != "object" || o == null ) s += pfx + tee + " (" + typeof(o) + ") " + o + "\n"; 221 | else { 222 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects 223 | let objectToInspect, properties = [], _listed = {}; 224 | for( objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect) ) 225 | properties = properties.concat(Object.getOwnPropertyNames(objectToInspect)); 226 | for ( let i of properties ) { 227 | try { 228 | if ( i in _listed || i in this.ignoreArray || i in this.ignoreMap || i in this.ignoreString ) continue; 229 | _listed[i] = true; 230 | s += this.dumpValue(o[i], i, recurse, compress, pfx, tee, level, ''); 231 | } catch (ex) { s += pfx + tee + " (exception) " + ex + "\n"; } 232 | } 233 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map, Map is not Object 234 | if ( typeof(o.keys) == 'function' && typeof(o.get) == 'function' ) { 235 | for ( let i of o.keys() ) { 236 | try { 237 | if ( i in _listed || i in this.ignoreArray || i in this.ignoreMap || i in this.ignoreString ) continue; 238 | _listed[i] = true; 239 | s += this.dumpValue(o.get(i), i, recurse, compress, pfx, tee, level, ' => '); 240 | } catch (ex) { s += pfx + tee + " (exception) " + ex + "\n"; } 241 | } 242 | } 243 | // nsIMsgDBHdr 244 | if ( typeof(o.propertyEnumerator) == 'object' && typeof(o.getStringProperty) == 'function' ) { 245 | let e = o.propertyEnumerator; 246 | while ( e.hasMore() ) { 247 | let i = e.getNext(); 248 | s += this.dumpValue(o.getStringProperty(i), i, recurse, compress, pfx, tee, level, ' -> '); 249 | } 250 | } 251 | } 252 | } catch (ex) { 253 | s += pfx + tee + " (exception) " + ex + "\n"; 254 | //this.logException(ex); 255 | } 256 | s += pfx + "*\n"; 257 | return s; 258 | }, 259 | 260 | logObject: function(obj, name, maxDepth, curDepth) { 261 | if (!this.verbose) return; 262 | console.dir(obj); 263 | this._checked = []; 264 | this.info(name + ": " + ( typeof(obj) == 'object' ? ( Array.isArray(obj) ? 'Array' : obj ) : '' ) + "\n" + this.objectTreeAsString(obj,maxDepth,true)); 265 | this._checked = []; 266 | }, 267 | 268 | logException: function(e, popup) { 269 | let msg = ""; 270 | if ( typeof(e) != 'string' ) { 271 | if ( 'name' in e && 'message' in e ) msg += e.name + ": " + e.message + "\n"; 272 | if ( 'stack' in e ) msg += e.stack; 273 | if ( 'location' in e ) msg += e.location + "\n"; 274 | } 275 | if ( msg == '' ) msg += " " + e + "\n"; 276 | msg = 'Caught Exception ' + msg; 277 | let fileName= e.fileName || e.filename || ( Cs.caller && Cs.caller.filename ); 278 | let lineNumber= e.lineNumber || ( Cs.caller && Cs.caller.lineNumber ); 279 | let sourceLine= e.sourceLine || ( Cs.caller && Cs.caller.sourceLine ); 280 | let scriptError = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError); 281 | scriptError.init(msg, fileName, sourceLine, lineNumber, e.columnNumber, scriptError.errorFlag, "chrome javascript"); 282 | Services.console.logMessage(scriptError); 283 | if ( typeof(popup) == 'undefined' || popup ) this.popup("Exception", msg); 284 | }, 285 | 286 | }; 287 | let popupWins = {}; 288 | -------------------------------------------------------------------------------- /src/content/aop.jsm: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery AOP - jQuery plugin to add features of aspect-oriented programming (AOP) to jQuery. 3 | * http://jquery-aop.googlecode.com/ 4 | * 5 | * Licensed under the MIT license: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Version: 1.3 9 | * 10 | * Cross-frame type detection based on Daniel Steigerwald's code (http://daniel.steigerwald.cz) 11 | * http://gist.github.com/204554 12 | * 13 | */ 14 | 15 | // Changed by Opera.Wang@gmail.com to make it loadable as an module 16 | // Removed 'jQuery.' as jQuery maybe not available 17 | // Removed IE stuff 18 | "use strict"; 19 | 20 | var EXPORTED_SYMBOLS = ["ldapInfoaop"]; 21 | 22 | var ldapInfoaop; 23 | 24 | Cu.import("resource://gre/modules/Services.jsm"); 25 | 26 | (function() { 27 | 28 | var _after = 1; 29 | var _afterThrow = 2; 30 | var _afterFinally = 3; 31 | var _before = 4; 32 | var _around = 5; 33 | var _intro = 6; 34 | var _regexEnabled = true; 35 | var _undef = 'undefined'; 36 | 37 | var isFunc = function(obj) { 38 | let type = typeof(obj); 39 | if ( type == 'function' && typeof(obj.call) != _undef ) return true; 40 | if ( type == 'object' && obj ) { 41 | let className = Object.prototype.toString.call( /** @type {Object} */ (obj)); 42 | if ((className == '[object Function]' || typeof obj.call != _undef 43 | && typeof obj.propertyIsEnumerable != _undef 44 | && !obj.propertyIsEnumerable('call'))) { 45 | return true; 46 | } 47 | } 48 | return false; 49 | }; 50 | 51 | /** 52 | * Private weaving function. 53 | */ 54 | var weaveOne = function(source, method, advice) { 55 | 56 | var old = source[method]; 57 | var aspect; 58 | if (advice.type == _after || advice.type == _afterThrow || advice.type == _afterFinally) 59 | aspect = function() { 60 | var returnValue, exceptionThrown = null; 61 | 62 | try { 63 | returnValue = old.apply(this, arguments); 64 | } catch (e) { 65 | exceptionThrown = e; 66 | } 67 | 68 | if (advice.type == _after) 69 | if (exceptionThrown == null) 70 | returnValue = advice.value.apply(this, [returnValue, method]); 71 | else 72 | throw exceptionThrown; 73 | else if (advice.type == _afterThrow && exceptionThrown != null) 74 | returnValue = advice.value.apply(this, [exceptionThrown, method]); 75 | else if (advice.type == _afterFinally) 76 | returnValue = advice.value.apply(this, [returnValue, exceptionThrown, method]); 77 | 78 | return returnValue; 79 | }; 80 | else if (advice.type == _before) 81 | aspect = function() { 82 | advice.value.apply(this, [arguments, method]); 83 | return old.apply(this, arguments); 84 | }; 85 | else if (advice.type == _intro) 86 | aspect = function() { 87 | return advice.value.apply(this, arguments); 88 | }; 89 | else if (advice.type == _around) { 90 | aspect = function() { 91 | var invocation = { object: this, args: Array.prototype.slice.call(arguments) }; 92 | return advice.value.apply(invocation.object, [{ arguments: invocation.args, method: method, proceed : 93 | function() { 94 | return old.apply(invocation.object, invocation.args); 95 | } 96 | }] ); 97 | }; 98 | } 99 | 100 | aspect.unweave = function() { 101 | source[method] = old; 102 | source = aspect = old = null; 103 | }; 104 | 105 | source[method] = aspect; 106 | 107 | return aspect; 108 | 109 | }; 110 | 111 | /** 112 | * Private method search 113 | */ 114 | var search = function(source, pointcut, advice) { 115 | 116 | var methods = []; 117 | 118 | for (var method in source) { 119 | 120 | var item = null; 121 | 122 | // Ignore exceptions during method retrival 123 | try { 124 | item = source[method]; 125 | } 126 | catch (e) { } 127 | 128 | if (item != null && method.match(pointcut.method) && isFunc(item)) 129 | methods[methods.length] = { source: source, method: method, advice: advice }; 130 | 131 | } 132 | 133 | return methods; 134 | }; 135 | 136 | /** 137 | * Private weaver and pointcut parser. 138 | */ 139 | var weave = function(pointcut, advice) { 140 | 141 | var source = typeof(pointcut.target.prototype) != _undef ? pointcut.target.prototype : pointcut.target; 142 | var advices = []; 143 | 144 | // If it's not an introduction and no method was found, try with regex... 145 | if (advice.type != _intro && typeof(source[pointcut.method]) == _undef) { 146 | 147 | // First try directly on target 148 | var methods = search(pointcut.target, pointcut, advice); 149 | 150 | // No method found, re-try directly on prototype 151 | if (methods.length == 0) 152 | methods = search(source, pointcut, advice); 153 | 154 | for (var i in methods) 155 | advices[advices.length] = weaveOne(methods[i].source, methods[i].method, methods[i].advice); 156 | 157 | } 158 | else 159 | { 160 | // Return as an array of one element 161 | advices[0] = weaveOne(source, pointcut.method, advice); 162 | } 163 | 164 | return _regexEnabled ? advices : advices[0]; 165 | 166 | }; 167 | 168 | ldapInfoaop = 169 | { 170 | /** 171 | * Creates an advice after the defined point-cut. The advice will be executed after the point-cut method 172 | * has completed execution successfully, and will receive one parameter with the result of the execution. 173 | * This function returns an array of weaved aspects (Function). 174 | * 175 | * @example jQuery.aop.after( {target: window, method: 'MyGlobalMethod'}, function(result) { 176 | * alert('Returned: ' + result); 177 | * return result; 178 | * } ); 179 | * @result Array 180 | * 181 | * @example jQuery.aop.after( {target: String, method: 'indexOf'}, function(index) { 182 | * alert('Result found at: ' + index + ' on:' + this); 183 | * return index; 184 | * } ); 185 | * @result Array 186 | * 187 | * @name after 188 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 189 | * @option Object target Target object to be weaved. 190 | * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. 191 | * @param Function advice Function containing the code that will get called after the execution of the point-cut. It receives one parameter 192 | * with the result of the point-cut's execution. The function can choose to return this same value or a different one. 193 | * 194 | * @type Array 195 | * @cat Plugins/General 196 | */ 197 | after : function(pointcut, advice) 198 | { 199 | return weave( pointcut, { type: _after, value: advice } ); 200 | }, 201 | 202 | /** 203 | * Creates an advice after the defined point-cut only for unhandled exceptions. The advice will be executed 204 | * after the point-cut method only if the execution failed and an exception has been thrown. It will receive one 205 | * parameter with the exception thrown by the point-cut method. 206 | * This function returns an array of weaved aspects (Function). 207 | * 208 | * @example jQuery.aop.afterThrow( {target: String, method: 'indexOf'}, function(exception) { 209 | * alert('Unhandled exception: ' + exception); 210 | * return -1; 211 | * } ); 212 | * @result Array 213 | * 214 | * @example jQuery.aop.afterThrow( {target: calculator, method: 'Calculate'}, function(exception) { 215 | * console.log('Unhandled exception: ' + exception); 216 | * throw exception; 217 | * } ); 218 | * @result Array 219 | * 220 | * @name afterThrow 221 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 222 | * @option Object target Target object to be weaved. 223 | * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. 224 | * @param Function advice Function containing the code that will get called after the execution of the point-cut. It receives one parameter 225 | * with the exception thrown by the point-cut method. 226 | * 227 | * @type Array 228 | * @cat Plugins/General 229 | */ 230 | afterThrow : function(pointcut, advice) 231 | { 232 | return weave( pointcut, { type: _afterThrow, value: advice } ); 233 | }, 234 | 235 | /** 236 | * Creates an advice after the defined point-cut. The advice will be executed after the point-cut method 237 | * regardless of its success or failure, and it will receive two parameters: one with the 238 | * result of a successful execution or null, and another one with the exception thrown or null. 239 | * This function returns an array of weaved aspects (Function). 240 | * 241 | * @example jQuery.aop.afterFinally( {target: window, method: 'MyGlobalMethod'}, function(result, exception) { 242 | * if (exception == null) 243 | * return 'Returned: ' + result; 244 | * else 245 | * return 'Unhandled exception: ' + exception; 246 | * } ); 247 | * @result Array 248 | * 249 | * @name afterFinally 250 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 251 | * @option Object target Target object to be weaved. 252 | * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. 253 | * @param Function advice Function containing the code that will get called after the execution of the point-cut regardless of its success or failure. 254 | * It receives two parameters, the first one with the result of a successful execution or null, and the second one with the 255 | * exception or null. 256 | * 257 | * @type Array 258 | * @cat Plugins/General 259 | */ 260 | afterFinally : function(pointcut, advice) 261 | { 262 | return weave( pointcut, { type: _afterFinally, value: advice } ); 263 | }, 264 | 265 | 266 | /** 267 | * Creates an advice before the defined point-cut. The advice will be executed before the point-cut method 268 | * but cannot modify the behavior of the method, or prevent its execution. 269 | * This function returns an array of weaved aspects (Function). 270 | * 271 | * @example jQuery.aop.before( {target: window, method: 'MyGlobalMethod'}, function() { 272 | * alert('About to execute MyGlobalMethod'); 273 | * } ); 274 | * @result Array 275 | * 276 | * @example jQuery.aop.before( {target: String, method: 'indexOf'}, function(index) { 277 | * alert('About to execute String.indexOf on: ' + this); 278 | * } ); 279 | * @result Array 280 | * 281 | * @name before 282 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 283 | * @option Object target Target object to be weaved. 284 | * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. 285 | * @param Function advice Function containing the code that will get called before the execution of the point-cut. 286 | * 287 | * @type Array 288 | * @cat Plugins/General 289 | */ 290 | before : function(pointcut, advice) 291 | { 292 | return weave( pointcut, { type: _before, value: advice } ); 293 | }, 294 | 295 | 296 | /** 297 | * Creates an advice 'around' the defined point-cut. This type of advice can control the point-cut method execution by calling 298 | * the functions '.proceed()' on the 'invocation' object, and also, can modify the arguments collection before sending them to the function call. 299 | * This function returns an array of weaved aspects (Function). 300 | * 301 | * @example jQuery.aop.around( {target: window, method: 'MyGlobalMethod'}, function(invocation) { 302 | * alert('# of Arguments: ' + invocation.arguments.length); 303 | * return invocation.proceed(); 304 | * } ); 305 | * @result Array 306 | * 307 | * @example jQuery.aop.around( {target: String, method: 'indexOf'}, function(invocation) { 308 | * alert('Searching: ' + invocation.arguments[0] + ' on: ' + this); 309 | * return invocation.proceed(); 310 | * } ); 311 | * @result Array 312 | * 313 | * @example jQuery.aop.around( {target: window, method: /Get(\d+)/}, function(invocation) { 314 | * alert('Executing ' + invocation.method); 315 | * return invocation.proceed(); 316 | * } ); 317 | * @desc Matches all global methods starting with 'Get' and followed by a number. 318 | * @result Array 319 | * 320 | * 321 | * @name around 322 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 323 | * @option Object target Target object to be weaved. 324 | * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. 325 | * @param Function advice Function containing the code that will get called around the execution of the point-cut. This advice will be called with one 326 | * argument containing one function '.proceed()', the collection of arguments '.arguments', and the matched method name '.method'. 327 | * 328 | * @type Array 329 | * @cat Plugins/General 330 | */ 331 | around : function(pointcut, advice) 332 | { 333 | return weave( pointcut, { type: _around, value: advice } ); 334 | }, 335 | 336 | /** 337 | * Creates an introduction on the defined point-cut. This type of advice replaces any existing methods with the same 338 | * name. To restore them, just unweave it. 339 | * This function returns an array with only one weaved aspect (Function). 340 | * 341 | * @example jQuery.aop.introduction( {target: window, method: 'MyGlobalMethod'}, function(result) { 342 | * alert('Returned: ' + result); 343 | * } ); 344 | * @result Array 345 | * 346 | * @example jQuery.aop.introduction( {target: String, method: 'log'}, function() { 347 | * alert('Console: ' + this); 348 | * } ); 349 | * @result Array 350 | * 351 | * @name introduction 352 | * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. 353 | * @option Object target Target object to be weaved. 354 | * @option String method Name of the function to be weaved. 355 | * @param Function advice Function containing the code that will be executed on the point-cut. 356 | * 357 | * @type Array 358 | * @cat Plugins/General 359 | */ 360 | introduction : function(pointcut, advice) 361 | { 362 | return weave( pointcut, { type: _intro, value: advice } ); 363 | }, 364 | 365 | /** 366 | * Configures global options. 367 | * 368 | * @name setup 369 | * @param Map settings Configuration options. 370 | * @option Boolean regexMatch Enables/disables regex matching of method names. 371 | * 372 | * @example jQuery.aop.setup( { regexMatch: false } ); 373 | * @desc Disable regex matching. 374 | * 375 | * @type Void 376 | * @cat Plugins/General 377 | */ 378 | setup: function(settings) 379 | { 380 | _regexEnabled = settings.regexMatch; 381 | } 382 | }; 383 | 384 | })(); 385 | -------------------------------------------------------------------------------- /src/content/ldapInfoPrefDialog.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 88 | 89 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |