From 133259425a25d64097b1efe074f0b917ea0f70a0 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Fri, 26 Sep 2008 21:08:26 +0000 Subject: [PATCH 1/7] NEWS Monotone-Parent: c465e35fc5f42324c08780dae83f7d225dca6e6a Monotone-Revision: b3afbde30d88c6ea366307b2bb45202fe90bd36f Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2008-09-26T21:08:26 Monotone-Branch: ca.inverse.sogo --- NEWS | 5 +++++ SoObjects/Contacts/SOGoContactLDAPFolder.m | 12 ++++++++++- SoObjects/SOGo/LDAPSource.m | 11 ++++++++++ UI/MailerUI/Dutch.lproj/Localizable.strings | 2 +- UI/MailerUI/English.lproj/Localizable.strings | 4 ++-- UI/MailerUI/French.lproj/Localizable.strings | 2 +- UI/MailerUI/German.lproj/Localizable.strings | 2 +- UI/MailerUI/Italian.lproj/Localizable.strings | 2 +- UI/MailerUI/Spanish.lproj/Localizable.strings | 2 +- UI/MailerUI/UIxMailAccountActions.m | 19 ++++++++++------- UI/MailerUI/UIxMailMainFrame.m | 5 ++--- UI/Templates/MailerUI/UIxMailMainFrame.wox | 7 ------ UI/WebServerResources/MailerUI.css | 16 ++++++++++---- UI/WebServerResources/MailerUI.js | 20 +++++------------- UI/WebServerResources/UIxMailEditor.js | 6 ++++++ UI/WebServerResources/quota-level-alert.png | Bin 4060 -> 4038 bytes UI/WebServerResources/quota-level-ok.png | Bin 4063 -> 4040 bytes UI/WebServerResources/quota-level-warn.png | Bin 4074 -> 4040 bytes UI/WebServerResources/quota-level.png | Bin 4075 -> 4039 bytes 19 files changed, 70 insertions(+), 45 deletions(-) diff --git a/NEWS b/NEWS index 9cb7d59c9..27425c856 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +1.0-2008XXYY (1.0) +------------------ +- added quota indicator in web mail module +- improved drag handles behavior + 1.0-20080826 (1.0 rc8) ---------------------- - fixed a bug that would prevent deleted event and tasks from being removed from the events and tasks list diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.m b/SoObjects/Contacts/SOGoContactLDAPFolder.m index 3e28d9230..b7d9cdfb9 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.m +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.m @@ -24,6 +24,7 @@ #import #import #import +#import #import #import @@ -187,8 +188,10 @@ NSEnumerator *oldRecords; NSDictionary *oldRecord; NSMutableDictionary *newRecord; - NSString *data; + NSString *data, *contactInfo; + NSUserDefaults *ud; + ud = [NSUserDefaults standardUserDefaults]; newRecords = [[NSMutableArray alloc] initWithCapacity: [records count]]; [newRecords autorelease]; @@ -237,6 +240,13 @@ data = @""; [newRecord setObject: data forKey: @"phone"]; + contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"]; + if ([contactInfo length] > 0) { + data = [oldRecord objectForKey: contactInfo]; + if ([data length] > 0) + [newRecord setObject: data forKey: @"contactInfo"]; + } + [newRecords addObject: newRecord]; oldRecord = [oldRecords nextObject]; } diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index dfc37d341..4f7ed3b6a 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import @@ -394,8 +395,12 @@ static int sizeLimit; - (NSArray *) _searchAttributes { + NSUserDefaults *ud; + NSString *contactInfo; + if (!searchAttributes) { + ud = [NSUserDefaults standardUserDefaults]; searchAttributes = [NSMutableArray new]; if (CNField) [searchAttributes addObject: CNField]; @@ -404,6 +409,12 @@ static int sizeLimit; [searchAttributes addObjectsFromArray: mailFields]; [searchAttributes addObjectsFromArray: [self _contraintsFields]]; [searchAttributes addObjectsFromArray: commonSearchFields]; + + // Add SOGoLDAPContactInfoAttribute from user defaults + contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"]; + if ([contactInfo length] > 0 && + ![searchAttributes containsObject: contactInfo]) + [searchAttributes addObject: contactInfo]; } return searchAttributes; diff --git a/UI/MailerUI/Dutch.lproj/Localizable.strings b/UI/MailerUI/Dutch.lproj/Localizable.strings index 16d9913bb..312a2cf02 100644 --- a/UI/MailerUI/Dutch.lproj/Localizable.strings +++ b/UI/MailerUI/Dutch.lproj/Localizable.strings @@ -203,7 +203,7 @@ "Operation failed" = "Operatie mislukt."; "Quota" = "Quota"; -"quotasFormat" = "%{0} van %{1} KB gebruikt (%{2}%)"; +"quotasFormat" = "%{0}% van %{1} MB gebruikt"; "Please select a message." = "Selecteer een bericht."; "Please select a message to print." = "Selecteer een bericht om af te drukken."; diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index 7320cca1d..e7a8816b8 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -218,8 +218,8 @@ = "Do you really want to move this folder into the trash ?"; "Operation failed" = "Operation failed"; -"Quota" = "Quota"; -"quotasFormat" = "%{0} used on %{1} Kb (%{2}%)"; +"Quota" = "Quota:"; +"quotasFormat" = "%{0}% used on %{1} MB"; "Please select a message." = "Please select a message."; "Please select a message to print." = "Please select a message to print."; diff --git a/UI/MailerUI/French.lproj/Localizable.strings b/UI/MailerUI/French.lproj/Localizable.strings index 698120403..ef5f2d51c 100644 --- a/UI/MailerUI/French.lproj/Localizable.strings +++ b/UI/MailerUI/French.lproj/Localizable.strings @@ -220,7 +220,7 @@ "Operation failed" = "L'opération a échoué."; "Quota" = "Quota"; -"quotasFormat" = "%{0} Ko utilisés sur %{1} (%{2}%)"; +"quotasFormat" = "%{0}% utilisé sur %{1} MO"; "Please select a message." = "Veuillez sélectionner un message."; "Please select a message to print." = "Veuillez sélectionner un message à imprimer."; diff --git a/UI/MailerUI/German.lproj/Localizable.strings b/UI/MailerUI/German.lproj/Localizable.strings index 9b9ee6586..2720198f9 100644 --- a/UI/MailerUI/German.lproj/Localizable.strings +++ b/UI/MailerUI/German.lproj/Localizable.strings @@ -203,7 +203,7 @@ "Operation failed" = "L'opération a échoué."; "Quota" = "Quota"; -"quotasFormat" = "%{0} von %{1} KB verwendet (%{2}%)"; +"quotasFormat" = "%{0}% von %{1} MB verwendet"; "Please select a message." = "Sie müssen eine Nachricht auswählen."; "Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen."; diff --git a/UI/MailerUI/Italian.lproj/Localizable.strings b/UI/MailerUI/Italian.lproj/Localizable.strings index 7057fb6e1..a6905f2ca 100644 --- a/UI/MailerUI/Italian.lproj/Localizable.strings +++ b/UI/MailerUI/Italian.lproj/Localizable.strings @@ -226,7 +226,7 @@ "Operation failed" = "Operazione non riuscita"; "Quota" = "Spazio usato"; -"quotasFormat" = "%{0} su %{1} Kb (%{2}%)"; +"quotasFormat" = "%{0}% usato su %{1} MB"; "Please select a message." = "Per favore seleziona un messaggio."; "Please select a message to print." = "Per favore seleziona un messaggio da stampare."; diff --git a/UI/MailerUI/Spanish.lproj/Localizable.strings b/UI/MailerUI/Spanish.lproj/Localizable.strings index 8822a297a..40f1baeb3 100644 --- a/UI/MailerUI/Spanish.lproj/Localizable.strings +++ b/UI/MailerUI/Spanish.lproj/Localizable.strings @@ -222,7 +222,7 @@ "Operation failed" = "Operación fallida"; "Quota" = "Quotas"; -"quotasFormat" = "%{0} de %{1} Kb usados (%{2}%)"; +"quotasFormat" = "%{0}% de %{1} MB usados"; "Please select a message." = "Seleccione un mensaje primero."; "Please select a message to print." = "Seleccione el mensaje que desea imprimir."; diff --git a/UI/MailerUI/UIxMailAccountActions.m b/UI/MailerUI/UIxMailAccountActions.m index a4277fede..753d5b4ed 100644 --- a/UI/MailerUI/UIxMailAccountActions.m +++ b/UI/MailerUI/UIxMailAccountActions.m @@ -134,7 +134,7 @@ NSString *inboxName; NSUserDefaults *ud; WOResponse *response; - int quota; + float quota; ud = [NSUserDefaults standardUserDefaults]; co = [self clientObject]; @@ -143,18 +143,21 @@ folders = [self _jsonFolders: rawFolders]; // Retrieve INBOX quota - quota = [ud integerForKey: @"SOGoSoftQuota"]; + quota = [ud floatForKey: @"SOGoSoftQuotaRatio"]; inbox = [co inboxFolderInContext: context]; inboxName = [NSString stringWithFormat: @"/%@", [inbox relativeImap4Name]]; client = [[inbox imap4Connection] client]; infos = [[client getQuotaRoot: [inbox relativeImap4Name]] objectForKey: @"quotas"]; inboxQuota = [infos objectForKey: inboxName]; - if (quota > 0 && inboxQuota != nil) - // A soft quota is imposed for all users - inboxQuota = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt: quota], @"maxQuota", - [inboxQuota objectForKey: @"usedSpace"], @"usedSpace", - nil]; + if (quota != 0 && inboxQuota != nil) + { + // A soft quota ration is imposed for all users + quota = quota * [(NSNumber*)[inboxQuota objectForKey: @"maxQuota"] intValue]; + inboxQuota = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithFloat: (long)(quota+0.5)], @"maxQuota", + [inboxQuota objectForKey: @"usedSpace"], @"usedSpace", + nil]; + } data = [NSDictionary dictionaryWithObjectsAndKeys: folders, @"mailboxes", inboxQuota, @"quotas", nil]; diff --git a/UI/MailerUI/UIxMailMainFrame.m b/UI/MailerUI/UIxMailMainFrame.m index b0956fdf9..65ad37976 100644 --- a/UI/MailerUI/UIxMailMainFrame.m +++ b/UI/MailerUI/UIxMailMainFrame.m @@ -20,7 +20,6 @@ */ #import -#import #import #import @@ -150,8 +149,8 @@ - (id ) composeAction { id contact; - NSArray *accounts, *contactsId; - NSString *firstAccount, *newLocation, *parameters, *folderId, *uid, *email, *n; + NSArray *accounts, *contactsId, *n; + NSString *firstAccount, *newLocation, *parameters, *folderId, *uid, *email; NSMutableString *fn; NSEnumerator *uids; NSMutableArray *addresses; diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index 96dc58464..fafe9f69f 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -191,13 +191,6 @@ - -
diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css index 0e8713c9b..0a098da8f 100644 --- a/UI/WebServerResources/MailerUI.css +++ b/UI/WebServerResources/MailerUI.css @@ -650,7 +650,7 @@ DIV.quota DIV.level background-position: 25% 0; border-left: 1px solid #999; border-right: 1px solid #999; - height: 20px; } + /*height: 20px;*/ } DIV.quota DIV.marks DIV { float: left; margin: 0; @@ -658,11 +658,11 @@ DIV.quota DIV.marks DIV width: 25%; border: 0; border-right: 1px solid #999; - height: 5px; } + height: 3px; } DIV.quota DIV.level DIV.value { background-repeat: repeat-x; border-left: 1px solid transparent; - height: 15px; + height: 9px; margin: 0; position: relative; } DIV.quota DIV.level DIV.value.ok @@ -670,7 +670,15 @@ DIV.quota DIV.level DIV.value.ok DIV.quota DIV.level DIV.value.warn { background-image: url(quota-level-warn.png); } DIV.quota DIV.level DIV.value.alert -{ background-image: url(quota-level-alert.png); } +{ background-image: url(quota-level-alert.png); } +DIV.quota DIV.level P +{ margin: 0; + padding: 0; + clear: both; + color: #555; + font-size: 1em; + text-align: center; +} DIV#quotaDialog { background-image: url("dialog-left.png"); background-repeat: no-repeat; diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index c0d4cce51..ee396fffe 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -1373,39 +1373,29 @@ function updateMailboxTreeInPage() { } } if (Mailer.quotas) { - // Build quota indicator + // Build quota indicator, show values in MB var percents = (Math.round(Mailer.quotas.usedSpace * 10000 / Mailer.quotas.maxQuota) / 100); var level = (percents > 85)? "alert" : (percents > 70)? "warn" : "ok"; var format = labels["quotasFormat"]; - var text = format.formatted(Mailer.quotas.usedSpace, Mailer.quotas.maxQuota, percents); + var text = format.formatted(percents, + Math.round(Mailer.quotas.maxQuota/10.24)/100); var quotaDiv = new Element('div', { 'class': 'quota', 'info': text }); var levelDiv = new Element('div', { 'class': 'level' }); var valueDiv = new Element('div', { 'class': 'value ' + level, 'style': 'width: ' + ((percents > 100)?100:percents) + '%' }); var marksDiv = new Element('div', { 'class': 'marks' }); + var textP = new Element('p').update(text); marksDiv.appendChild(new Element('div')); marksDiv.appendChild(new Element('div')); marksDiv.appendChild(new Element('div')); levelDiv.appendChild(valueDiv); levelDiv.appendChild(marksDiv); + levelDiv.appendChild(textP); quotaDiv.appendChild(levelDiv); treeContent.insertBefore(quotaDiv, tree); - quotaDiv.observe("mouseover", onViewQuota); - quotaDiv.observe("mouseout", function(event) { $("quotaDialog").hide(); }); } } -function onViewQuota(event) { - var div = $("quotaDialog"); - if (div.visible()) return; - var position = this.cumulativeOffset(); - position[0] += this.getWidth(); - div.down("p").update(this.readAttribute("info")); - div.setStyle({ left: position[0] + "px", - top: position[1] + "px" }); - div.show(); -} - function mailboxMenuNode(type, name) { var newNode = document.createElement("li"); var icon = MailerUIdTreeExtension.folderIcons[type]; diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index 64b970e37..ba924ea1f 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -437,6 +437,12 @@ function performSearchCallback(http) { list.appendChild(node); node.uid = contact["c_uid"]; node.appendChild(document.createTextNode(completeEmail)); + log($H(contact).inspect() + ""); + if (contact["contactInfo"]) { + var info = new Element('span').update(contact['contactInfo']); + node.appendChild(info); + log ("info = " + contact['contactInfo']); + } $(node).observe("mousedown", onAddressResultClick); } diff --git a/UI/WebServerResources/quota-level-alert.png b/UI/WebServerResources/quota-level-alert.png index 4383a284462d398e0db7d398f456358df4811bbc..5ac2167b76c2b6223d5f98040a7230c5b10055b0 100644 GIT binary patch literal 4038 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 R7DWI6002ovPDHLkV1hsd;f(+Q diff --git a/UI/WebServerResources/quota-level-warn.png b/UI/WebServerResources/quota-level-warn.png index 2b0712fc25ef5ae11758fa59f07c8513ae88368b..793091a8ba611076d673915e1e7b7065c40eb7ec 100644 GIT binary patch literal 4040 zcmV;(4>$0MP)4Tx0C)kdSanpCP1~Psy1QIL%3WCLkXn%L4wYOQ7FkL_5KvGI1f&E(%EAB< zK~PZ<&_@Xo5q%Iu6h%=wB;=h1ecmt5d%l0ZIcM+r&2O%ld#<_XnppriMZ6;-LXiM~ zu<)ozdlNF=)y*A`8w6;81k6AJh@xTdN`Gj!Nazp%1OXB}0b5v~j(xVUBOS*^MMOcFKsxpf^!9@|5n@85qrD-- zmmp>f*uqV8?6ZZR&~c1!09|(w04!IyUr;yzxJih0{U|hF*iHBA=STAmgZMN6NZqh7 zDzwkh3wc@Jh)Af*u?(>keO_Pn<5<`67o05HQF8*|cdY&ig|XK!q*R%~pnR|0?<0^mWYZ**kLrYw9B zL>B=6S9|N7e`}y%aA1HDM^HlO3)r2wJB-FmFIe`lPO?)umbub+xOva=O9|8nsR%cU z?h#Z(9FHZj< znaR-B==APx6J}FGvjp=S79XrQt@Ug|Z1e2y+kbLob|N`DxJ0|=yWMsl@R-}nxlhs4 z!Yj}_&8O7&j$a>TG5`}O7Nizz6+#J32+IzyrrwEozJEA!inbBW8Y3Jl6Q^`QJKiwC zJkjQ$U6Mnx!y&sAt5lOT{ln@bGsqid^)9Tqm*=sq& zx%bbU%S*_2D^M-uESxOrJX>BIU*d31z7$#drtHS~BjxTD3YEypfvU^Zi5ILd;xEo# zYP)>qif@hbRn*nKYvtFeH*{*5YX|Et+@#g(-(tBn*idylqEWjE*VK3CTysE+Qp?)i z&U@MS-CHGFzdyMBFzJy=8++U9$7SsS9SR)_op+z4J~jP|?XQ>53ZL)o67TxdeYq#J zSFv~YMMGcgOO2N+{VlH&2X+mtzrH(|_(uE9>f7eOG1H;3MiQ;U_~O_$vjd1!@K91sjGKhnj_1gj-W>B5e2DM%vJ< zqb#FMV~k?;;xrHJjF(N=mdJCE;oxf0_vGP2-6{7{Ytjl1ryU7Pch1l|Dt(OQ*lgzO z*8|~t;Hn+3Yq@#4o^ng8furHm z?dHbQP5yUunz@_5wmi67aF2T5q;*^C@`JvIS0AOfc|X=^7i?eb=l*Fu?77~X|020B=%r)7{wsw6k=M+xR|hBGjJ)mpyJM*NUG4CNk&^ehqnRI4 z#^OFwKlzXE`E2*actYzd;hWeb+vM8!FF*RGny1TV(q{eU$n)Fge=hVaRxQOW8~^0_ z`F`c{YQ&oQ+WPv#UuheLoAE~>2`D|Z6DACsi7RKg!`Q?0nFYzp&qid|=Wyi=<4WPq z<+;S$!q>$=EHEXwA$jg-BUrsSYZQejdVQ*BW@t?s9xp^4KR(5lkjze`sKr_-xjr017l&`y{Bt${yr~HdCz&T``*WV9DK!mzxv&#r21P22nBo&ycLuZY!f09 z@-?(6EIr(jDnXrzXx)D*(t{>PTZ(Fr&W-VkCC2`YYd?@3zc)c9VJ5NV;E^P&WZvX= zhpJM7Q%R`{Y0Za|j*!za>75ywM=g%A9_!A`I&O1<{Y3Z4Q>U!6ShKoLpUAe%Va|D$ zn|a1Ok16k2{)qysLbk%*qTI92#e&7}O3Kd#loCtl%UaH-m0MQuRg6|%tvUc#7T<;O zi;b5uFYmjeQo~&H@oMX}lIw{#JZlZ>cHHEv$J8(1nrirVd$Muv4x*X2g>={9Uef)W ztuqg`9-VBPYK2=K=s9%%irf061y_9DSl+PeuvW3Lu*I^CvD>q^aj0?B za7u6%bMbNIa&y5|%*RvAE5TdCr^@$;-;RG&fF_6&ED=%>>JknV!H86e8i|gJWo{#F z8^ouG6UE<3WJ+pFPDxd7-z&{8-7k|X>nJBEHzI#|M>N5R$VZ%1c&u1PO4{iKcRxiH z5mgp7pth_&r!lL!ptZUStHYx!t*5Q;WDrTtF>Ev%F=jH+Gz~SYFdwoMv~sgPXYs%v>`JxH%T(}J zv0Ol30$0FQ^mXQ1{+rUbG;Uir1vVePTY3NSgU@Zu?W9iUrwPx>x*qn7zF6<)A0Q6u zzBM1R8+Lqe|H1sD?l|!a|HQ9v@4vTB70*P^SuWrgXP2L>6t9K+(xk5+c!t2h6CoE6 z0n$JT=mQ(z1tP%_a2C{pPVgSAAb1f<2pdE=A`4NAc!^j-iXh3zU}P@x9&!T3i!wyf zP?e}xXa=+nnuflD9>a)Y+%Wl=S6E)G3$_^h9w&pN;+h$-42}#{42z8BjOC0!nH-pE znc0~mm|wDJvXry3upVIj!sgD_!*0yp%Aw8C%&E=U%C(!Ti`$j^6HhcRmiH{*PQIu7 zegZ(COi)kogHVPrQFuV)kSIa)EsXiDZPWN_@jViJ5-%iANm*@Y-`*!(DB~$BC%Yi` zSUzt@AVHVNPn=cgRjecB?MzgnDBG)$RaMn?s7q?LSWAiYktgj;%jHj(?fxe{d~1H)Tg^$6=pzka7N)e&&Z0 z>8Iqgda|Q)Mb5P4hZOP@-7EG#$6nfW-n)XSvc7uHMa-pZSDb5pU8}xfRXcyP_!hZg zqA}}^TJyWRhwl?w`yU=`lX=|Nk^DsA>F~4cE|cz!-j=?Ee!T(Q>sN0s{hj*GXT*F| zbBy#!@w57b`8Ue<%&9vwGxN%eNy}ZU+t-h7#vcV30XM({5+DN?Kn2IZ1<(%05ljdY z!VQrIV?Ki9MD9k$BkPghQSzuD)D_eZv*ka{}`QO9m@9{HitC`q(2lxHy_P{kXWfI=Pd1cJZw9KH@vh?r=@3Q7G>AvaXWYjl0+2+Q$q8)}4U7HM^AFYD~k_0lWQ?%!G^cN1O3$h6Q5}FxKqQ2RmLDPtujH!y-7cY`9bg(R$ zl0rybJp3^I)X_begyZWcd$KBE)J*e4^Jfa%&z>y_FEu#NQ$AkVSe9Y8hZ&&ND z$JVOX&DURR@NQ&pYHIdqS-N+!Rro>0Bk{Jvc7~3K&KFPR|B8S1s0-b#-xJk){zYfs zL_hKs|A5SE(xB=a)wiU-Wru{`F}<4~9vW$VUp|`j!EKE65&QA=r%U6}pUGbszw}My ze|7&R@@;6c}~^3c=wYWNh{uCVEh%NmijqM?Zb`Y+? z-sZLtvq2n833qb%&BsNAZr*X}GMN!kWV*Zn#3dBk?msfO;sYIFp4`;!h>W&(f>;X5 z^oLL_=<;-5%YGE2-(y3f!$YktArHrlL4DEDzw?vIr7W;^JAXc2+`roEU=oe(e%b;3M@QX`?QE$dH#FXX&I_#cK; zLz*D1{b_A_4BhnlN5cZP{yVc}X=`*_Jwd<^O8wz||7g%Xhu!p#DWo3Iat=gGqm|IA zXfoXOb4Tx0C=30S9eg;-O}D)DiC__h9b=bA{~($r1xG_1QLpr#DpdwC@3fv1f&U~ zG)1wXh#;ug0DTouL_}W%D~h7@BE{T4P~UIvojZ5F{o~AYp0j)Q*_|_UW&wm`gP6=H z6aYlW#IoFNEQ!8;{zUu$U;qUKPz1T45H{1o)zuOHtIhQT0s!!g9K>Ws`4D<|Ec5&+O> z?2u>x{-XdW)97dh4M6Y-0H}p9S+M|u3jm<(>*r5gl^l=)pxX(6Yxsv_w*xd-0m#q% z!>JwvkQ4;Ckopfd?G6Y4AmTmjP#tXm06=&x0kA_H&a?^uJ`Z3em%~}A!F#(3)f^deYh}dxn zWyv~eU704ijq>-1HVPd|w#xTatX138jWp^>YUJZue3Yd1A9Y-G8}y|N5)At`Xc_O@ z_{x-ImS}#*l85SQb#zm=4Z)Ubmu!E@;hmF^vzbezYk}J>_m7?gFN(K^Pn>U|-!=dK zfaxtlTeSimwuJ{}1eb?gr}fgu!m#1;5&GMmBI!}d(YY}-jO)zDJBC=}Y)%|syi9^> zqV`VXBxD! zHOQ6DUCtZIzjf?HL2{vAkzTP-@mNXc@ru%e|73euhi1oY=Zy#H4{iVA|LfVK;>TOM z6uLfkpY4fyqV;6zX=87~Gs9<#eXY+^`ZxBkytpxt^3wR_(yNxg69)|j=U!hOVh?K% zPrkYQcE>yIchm11KO}xM89|La{FL{3^Qh|R?3ebhMPpIlsNZG3&yV*{G)n#M$7zu_ae-t+hnp7S~IKM*t(Y7!xf zo)wpo$d}@hPLr9Iqsu=h+9@r%3m`zNSH} zVUy9UvG&F&lM2&k<`@f#r9U;zs%lfa^?MtRowU8SgNVgLbb#6!#6~jZKpSbs0r_GxkMidS{vK zS2@6YU@H5?!Ineihj$+d%CS7EkPEp(c{lP)j>Q$Y6_Sc@MQ@6)m*gGaUTRq;RW@;= zv;4$K_9?px`HGp!hgId(tQwosvZp7`wAYrLjX7soCtmmU{Ot?JE{0z+sTZyvx!ii? zXaoJ~hDO20kJnn7jy8v0H)#=R`O+6?1`jmBl;E4Z$6_wan;Me#}S zlLgELeTAZh_lV?+){3=?cS#IMj!SW5_+(||)a13-7!fTL>=Yf8oRwYII;+^LZc;N* z*VRy6CrRQa&5(yRJGCxQa@Vu9J#;9#Ji71oTJ?__&U_Un$?We&_sI0mhp#o4d9YZrv8B5jeB$R?vZ9j}ZBgFSKj)^ibz8 z>99}XS0napcZrmZ{1Vk1of+fFP-ILp+jbmb1+dlG^Rex5`SIHl$O%6Z+jr(BZAn&5 zo=j=owJ+5vO)Ty8?&>|;(<$k*87+HL_gQ9QGdr`g_d6WmJJ6k-bI|3Gz@hHLM~*n> z@a1$JJ(TO1N634WpMA`}fT!S5;h`d@V*cVMCHcp_OQlL*msOkyD<_xFoNPUnQQ=rA zUir4_eD%&6o73W_N6s|WW}n@9PPdLw_u+iog|dq&mjdglm)BhpZ@@MzTpe%xdTp#} z`a04g)=IhIaWnPSmA1({8}1&yH`eak(fz>d;mD)?T}IvWPww|t_T}^+94LC#F!=Yd z*xN1dFOLX+-t%SQTk-^c>g24>eD7lNiZ+J>u=@7_0O0fiigE#bn*qEm01k-(sQCbh z*8;fm0eBh#YN85Ijdua5o&EiP00LOx0U?kACC~z6umeAcfMhrVmCy`5@CgA#8qq`C z5e9Muxrp>2lPEEi5h@V14|M_6j|Mae?TgMtH=;ja#4)y*6wGDJC#*cy2b+t1jN``H z;<9iL@C3XI{uq9cOPPzo)ymDy?aO_Zdzr_LrvaXRo2G86fUaAS=95%vLg18dt7ayG2DprB5|q%~M@UeOTk{x;T;*S)4qkd0*=! zC3XEaZEGDZU0FR|eb8Spm^Pd;n%%Ip5oaQ5s$ynr?q$KU%%e704O{cr7}-YIRoV|a zN;&yCpK$r;rsclNqsL3xJH=+@|^LCqnWv@@Z~VKotI+b=~KMz=G( zn4_$;Sjo7?1kc3zq!TIDyC&04?QzfG+Iu@QWxw%(m4kN=AI$N|Rn1#G_O$SParW`Z zGPm*#r&KE?s(DXiYT+E5$6O@TOI%U8YIx1LIlN`>jjCJsZ-2T+Xs2{~KTLjfvg=OI z+ovmi68+=>(^vL`ZbP1L+~3)MFdZR(mKgo{_06}o@zTk-X~$XO+|2L-W}~an&oNvW6AT-34)Y!>hxNl2VxQy0a6Y(F+#9?qo`G-S!f|sspR>8~?THY6GmHz*maZ`3g{H+40m znI~HmST<1mtQM?^HV(E)cIWNiI!ZfvI~TYNxXHVRd0h3vc>DNV@Wc5B2i)1Bv^6Vm zJjgG&gQiD66DAX$x1A7~6^)76%f#R%f`{Boa_26uW#(VMQZE2v+JJf{oanW2bvFu9_4n~baS4x_9pk4_2XYWe_8u? z`s?6f`?p5#DIc{y8I0P0rGLvFzdkuRqcfMf(6zL7Wj}`l0BGO_5g-BuEWrmDZ~#t2 zJB%Pa2nF#&GLU*?7$t<-gi1m+puV9s&=Kf!=dCLLTk+>=w88<%feAXhk9+9Pfk7U>>cexJ(uWLeL)$}d#U$|^0(Tc^lP5iGed*JZEq^xroQugPx*lR@Zw|b zNZcpO&)lDTM+?9Bf0g|@I9B$}_q*8lp7H$?7847Tm!@dblGBf8QfJrCzL`5ZZ!tf; zQ1ioc5wqB^v~8Jxxn+g+lmBNU$DhLiSe=&u0Dy5F7Ixc|zvK%-mz(uTssL^(UIYDS4h#M*fRfG7Y;1FRtkSP%wuAcG@N z!RpsagdiXS6&Sz*I`$K6-UR=t(E*}> z4spN&I>h`(ze4_x8d#m(0RV7<0A+yy0Jr7nyZ`;2#nKaF0RX5B=1x{bSa>Yag2{}c zlZbXPA(|wjHicpc{{rBdRySUZ3`PI|08>dsK~xBtbM^I5^xZgRl=+SXzm?1o7((mKxCNKDG~FC+#fgq c<6NP)4Tx0C)kdSanpCP1~Psy1QIL%3WCLkXn%L4wYOQ7FkL_5KvGI1f&E(%EAB< zK~PZ<&_@Xo5q%Iu6h%=wB;=h1ecmt5d%l0ZIcM+r&2O%ld#<_XnppriMZ6;-LXiM~ zu<)ozdlNF=)y*A`8w6;81k6AJh@xTdN`Gj!Nazp%1OXB}0b5v~j(xVUBOS*^MMOcFKsxpf^!9@|5n@85qrD-- zmmp>f*uqV8?6ZZR&~c1!09|(w04!IyUr;yzxJih0{U|hF*iHBA=STAmgZMN6NZqh7 zDzwkh3wc@Jh)Af*u?(>keO_Pn<5<`67o05HQF8*|cdY&ig|XK!q*R%~pnR|0?<0^mWYZ**kLrYw9B zL>B=6S9|N7e`}y%aA1HDM^HlO3)r2wJB-FmFIe`lPO?)umbub+xOva=O9|8nsR%cU z?h#Z(9FHZj< znaR-B==APx6J}FGvjp=S79XrQt@Ug|Z1e2y+kbLob|N`DxJ0|=yWMsl@R-}nxlhs4 z!Yj}_&8O7&j$a>TG5`}O7Nizz6+#J32+IzyrrwEozJEA!inbBW8Y3Jl6Q^`QJKiwC zJkjQ$U6Mnx!y&sAt5lOT{ln@bGsqid^)9Tqm*=sq& zx%bbU%S*_2D^M-uESxOrJX>BIU*d31z7$#drtHS~BjxTD3YEypfvU^Zi5ILd;xEo# zYP)>qif@hbRn*nKYvtFeH*{*5YX|Et+@#g(-(tBn*idylqEWjE*VK3CTysE+Qp?)i z&U@MS-CHGFzdyMBFzJy=8++U9$7SsS9SR)_op+z4J~jP|?XQ>53ZL)o67TxdeYq#J zSFv~YMMGcgOO2N+{VlH&2X+mtzrH(|_(uE9>f7eOG1H;3MiQ;U_~O_$vjd1!@K91sjGKhnj_1gj-W>B5e2DM%vJ< zqb#FMV~k?;;xrHJjF(N=mdJCE;oxf0_vGP2-6{7{Ytjl1ryU7Pch1l|Dt(OQ*lgzO z*8|~t;Hn+3Yq@#4o^ng8furHm z?dHbQP5yUunz@_5wmi67aF2T5q;*^C@`JvIS0AOfc|X=^7i?eb=l*Fu?77~X|020B=%r)7{wsw6k=M+xR|hBGjJ)mpyJM*NUG4CNk&^ehqnRI4 z#^OFwKlzXE`E2*actYzd;hWeb+vM8!FF*RGny1TV(q{eU$n)Fge=hVaRxQOW8~^0_ z`F`c{YQ&oQ+WPv#UuheLoAE~>2`D|Z6DACsi7RKg!`Q?0nFYzp&qid|=Wyi=<4WPq z<+;S$!q>$=EHEXwA$jg-BUrsSYZQejdVQ*BW@t?s9xp^4KR(5lkjze`sKr_-xjr017l&`y{Bt${yr~HdCz&T``*WV9DK!mzxv&#r21P22nBo&ycLuZY!f09 z@-?(6EIr(jDnXrzXx)D*(t{>PTZ(Fr&W-VkCC2`YYd?@3zc)c9VJ5NV;E^P&WZvX= zhpJM7Q%R`{Y0Za|j*!za>75ywM=g%A9_!A`I&O1<{Y3Z4Q>U!6ShKoLpUAe%Va|D$ zn|a1Ok16k2{)qysLbk%*qTI92#e&7}O3Kd#loCtl%UaH-m0MQuRg6|%tvUc#7T<;O zi;b5uFYmjeQo~&H@oMX}lIw{#JZlZ>cHHEv$J8(1nrirVd$Muv4x*X2g>={9Uef)W ztuqg`9-VBPYK2=K=s9%%irf061y_9DSl+PeuvW3Lu*I^CvD>q^aj0?B za7u6%bMbNIa&y5|%*RvAE5TdCr^@$;-;RG&fF_6&ED=%>>JknV!H86e8i|gJWo{#F z8^ouG6UE<3WJ+pFPDxd7-z&{8-7k|X>nJBEHzI#|M>N5R$VZ%1c&u1PO4{iKcRxiH z5mgp7pth_&r!lL!ptZUStHYx!t*5Q;WDrTtF>Ev%F=jH+Gz~SYFdwoMv~sgPXYs%v>`JxH%T(}J zv0Ol30$0FQ^mXQ1{+rUbG;Uir1vVePTY3NSgU@Zu?W9iUrwPx>x*qn7zF6<)A0Q6u zzBM1R8+Lqe|H1sD?l|!a|HQ9v@4vTB70*P^SuWrgXP2L>6t9K+(xk5+c!t2h6CoE6 z0n$JT=mQ(z1tP%_a2C{pPVgSAAb1f<2pdE=A`4NAc!^j-iXh3zU}P@x9&!T3i!wyf zP?e}xXa=+nnuflD9>a)Y+%Wl=S6E)G3$_^h9w&pN;+h$-42}#{42z8BjOC0!nH-pE znc0~mm|wDJvXry3upVIj!sgD_!*0yp%Aw8C%&E=U%C(!Ti`$j^6HhcRmiH{*PQIu7 zegZ(COi)kogHVPrQFuV)kSIa)EsXiDZPWN_@jViJ5-%iANm*@Y-`*!(DB~$BC%Yi` zSUzt@AVHVNPn=cgRjecB?MzgnDBG)$RaMn?s7q?LSWAiYktgj;%jHj(?fxe{d~1H)Tg^$6=pzka7N)e&&Z0 z>8Iqgda|Q)Mb5P4hZOP@-7EG#$6nfW-n)XSvc7uHMa-pZSDb5pU8}xfRXcyP_!hZg zqA}}^TJyWRhwl?w`yU=`lX=|Nk^DsA>F~4cE|cz!-j=?Ee!T(Q>sN0s{hj*GXT*F| zbBy#!@w57b`8Ue<%&9vwGxN%eNy}ZU+t-h7#vcV30XM({5+DN?Kn2IZ1<(%05ljdY z!VQrIV?Ki9MD9k$BkPghQSzuD)D_eZv*ka{}`QO9m@9{HitC`q(2lxHy_P{kXWfI=Pd1cJZw9KH@vh?r=@3Q7G>AvaXWYjl0+2+Q$q8)}4U7HM^AFYD~k_0lWQ?%!G^cN1O3$h6Q5}FxKqQ2RmLDPtujH!y-7cY`9bg(R$ zl0rybJp3^I)X_begyZWcd$KBE)J*e4^Jfa%&z>y_FEu#NQ$AkVSe9Y8hZ&&ND z$JVOX&DURR@NQ&pYHIdqS-N+!Rro>0Bk{Jvc7~3K&KFPR|B8S1s0-b#-xJk){zYfs zL_hKs|A5SE(xB=a)wiU-Wru{`F}<4~9vW$VUp|`j!EKE65&QA=r%U6}pUGbszw}My ze|7&R@@;6c}~^3c=wYWNh{uCVEh%NmijqM?Zb`Y+? z-sZLtvq2n833qb%&BsNAZr*X}GMN!kWV*Zn#3dBk?msfO;sYIFp4`;!h>W&(f>;X5 z^oLL_=<;-5%YGE2-(y3f!$YktArHrlL4DEDzw?vIr7W;^JAXc2+`roEU=oe(e%b;3M@QX`?QE$dH#FXX&I_#cK; zLz*D1{b_A_4BhnlN5cZP{yVc}X=`*_Jwd<^O8wz||7g%Xhu!p#DWo3Iat=gGqm|IA zXfoXOb4Tx0C=30S9eg;-O}D)DiC__h9b=bA{~($r1xG_1QLpr#DpdwC@3fv1f&U~ zG)1wXh#;ug0DTouL_}W%D~h7@BE{T4P~UIvojZ5F{o~AYp0j)Q*_|_UW&wm`gP6=H z6aYlW#IoFNEQ!8;{zUu$U;qUKPz1T45H{1o)zuOHtIhQT0s!!g9K>Ws`4D<|Ec5&+O> z?2u>x{-XdW)97dh4M6Y-0H}p9S+M|u3jm<(>*r5gl^l=)pxX(6Yxsv_w*xd-0m#q% z!>JwvkQ4;Ckopfd?G6Y4AmTmjP#tXm06=&x0kA_H&a?^uJ`Z3em%~}A!F#(3)f^deYh}dxn zWyv~eU704ijq>-1HVPd|w#xTatX138jWp^>YUJZue3Yd1A9Y-G8}y|N5)At`Xc_O@ z_{x-ImS}#*l85SQb#zm=4Z)Ubmu!E@;hmF^vzbezYk}J>_m7?gFN(K^Pn>U|-!=dK zfaxtlTeSimwuJ{}1eb?gr}fgu!m#1;5&GMmBI!}d(YY}-jO)zDJBC=}Y)%|syi9^> zqV`VXBxD! zHOQ6DUCtZIzjf?HL2{vAkzTP-@mNXc@ru%e|73euhi1oY=Zy#H4{iVA|LfVK;>TOM z6uLfkpY4fyqV;6zX=87~Gs9<#eXY+^`ZxBkytpxt^3wR_(yNxg69)|j=U!hOVh?K% zPrkYQcE>yIchm11KO}xM89|La{FL{3^Qh|R?3ebhMPpIlsNZG3&yV*{G)n#M$7zu_ae-t+hnp7S~IKM*t(Y7!xf zo)wpo$d}@hPLr9Iqsu=h+9@r%3m`zNSH} zVUy9UvG&F&lM2&k<`@f#r9U;zs%lfa^?MtRowU8SgNVgLbb#6!#6~jZKpSbs0r_GxkMidS{vK zS2@6YU@H5?!Ineihj$+d%CS7EkPEp(c{lP)j>Q$Y6_Sc@MQ@6)m*gGaUTRq;RW@;= zv;4$K_9?px`HGp!hgId(tQwosvZp7`wAYrLjX7soCtmmU{Ot?JE{0z+sTZyvx!ii? zXaoJ~hDO20kJnn7jy8v0H)#=R`O+6?1`jmBl;E4Z$6_wan;Me#}S zlLgELeTAZh_lV?+){3=?cS#IMj!SW5_+(||)a13-7!fTL>=Yf8oRwYII;+^LZc;N* z*VRy6CrRQa&5(yRJGCxQa@Vu9J#;9#Ji71oTJ?__&U_Un$?We&_sI0mhp#o4d9YZrv8B5jeB$R?vZ9j}ZBgFSKj)^ibz8 z>99}XS0napcZrmZ{1Vk1of+fFP-ILp+jbmb1+dlG^Rex5`SIHl$O%6Z+jr(BZAn&5 zo=j=owJ+5vO)Ty8?&>|;(<$k*87+HL_gQ9QGdr`g_d6WmJJ6k-bI|3Gz@hHLM~*n> z@a1$JJ(TO1N634WpMA`}fT!S5;h`d@V*cVMCHcp_OQlL*msOkyD<_xFoNPUnQQ=rA zUir4_eD%&6o73W_N6s|WW}n@9PPdLw_u+iog|dq&mjdglm)BhpZ@@MzTpe%xdTp#} z`a04g)=IhIaWnPSmA1({8}1&yH`eak(fz>d;mD)?T}IvWPww|t_T}^+94LC#F!=Yd z*xN1dFOLX+-t%SQTk-^c>g24>eD7lNiZ+J>u=@7_0O0fiigE#bn*qEm01k-(sQCbh z*8;fm0eBh#YN85Ijdua5o&EiP00LOx0U?kACC~z6umeAcfMhrVmCy`5@CgA#8qq`C z5e9Muxrp>2lPEEi5h@V14|M_6j|Mae?TgMtH=;ja#4)y*6wGDJC#*cy2b+t1jN``H z;<9iL@C3XI{uq9cOPPzo)ymDy?aO_Zdzr_LrvaXRo2G86fUaAS=95%vLg18dt7ayG2DprB5|q%~M@UeOTk{x;T;*S)4qkd0*=! zC3XEaZEGDZU0FR|eb8Spm^Pd;n%%Ip5oaQ5s$ynr?q$KU%%e704O{cr7}-YIRoV|a zN;&yCpK$r;rsclNqsL3xJH=+@|^LCqnWv@@Z~VKotI+b=~KMz=G( zn4_$;Sjo7?1kc3zq!TIDyC&04?QzfG+Iu@QWxw%(m4kN=AI$N|Rn1#G_O$SParW`Z zGPm*#r&KE?s(DXiYT+E5$6O@TOI%U8YIx1LIlN`>jjCJsZ-2T+Xs2{~KTLjfvg=OI z+ovmi68+=>(^vL`ZbP1L+~3)MFdZR(mKgo{_06}o@zTk-X~$XO+|2L-W}~an&oNvW6AT-34)Y!>hxNl2VxQy0a6Y(F+#9?qo`G-S!f|sspR>8~?THY6GmHz*maZ`3g{H+40m znI~HmST<1mtQM?^HV(E)cIWNiI!ZfvI~TYNxXHVRd0h3vc>DNV@Wc5B2i)1Bv^6Vm zJjgG&gQiD66DAX$x1A7~6^)76%f#R%f`{Boa_26uW#(VMQZE2v+JJf{oanW2bvFu9_4n~baS4x_9pk4_2XYWe_8u? z`s?6f`?p5#DIc{y8I0P0rGLvFzdkuRqcfMf(6zL7Wj}`l0BGO_5g-BuEWrmDZ~#t2 zJB%Pa2nF#&GLU*?7$t<-gi1m+puV9s&=Kf!=dCLLTk+>=w88<%feAXhk9+9Pfk7U>>cexJ(uWLeL)$}d#U$|^0(Tc^lP5iGed*JZEq^xroQugPx*lR@Zw|b zNZcpO&)lDTM+?9Bf0g|@I9B$}_q*8lp7H$?7847Tm!@dblGBf8QfJrCzL`5ZZ!tf; zQ1ioc5wqB^v~8Jxxn+g+lmBNU$DhLiSe=&u0Dy5F7Ixc|zvK%-mz(uTssL^(UIYDS4h#M*fRfG7Y;1FRtkSP%wuAcG@N z!RpsagdiXS6&Sz*I`$K6-UR=t(E*}> z4spN&I>h`(ze4_x8d#m(0RV7<0A+yy0Jr7nyZ`;2#nKaF0RX5B=1x{bSa>Yag2{}c zlZbXPA(|wjHicpc{{rBdRySUZ3`PI|08~jtK~xBtU5r5vz#s?&7qdZ6{=)yq*P$2n zfGugcz+~8!-aCN3HvqQQ@C<9M0XgS*TWf_GV+5F)Un0UeXP8gM*KH#iMpZoxfTfhb dxsXzN;Q)OG8uI_9^Z5V(002ovPDHLkV1l6W>v;eG From e69d7b412512a97b03e3312bb073a6f87da5f239 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Mon, 29 Sep 2008 14:36:18 +0000 Subject: [PATCH 2/7] Monotone-Parent: b3afbde30d88c6ea366307b2bb45202fe90bd36f Monotone-Revision: f3553f7157471c92e062fbcc05707ec8f12c2df5 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2008-09-29T14:36:18 Monotone-Branch: ca.inverse.sogo --- SoObjects/Contacts/SOGoContactLDAPFolder.m | 12 +----------- SoObjects/SOGo/LDAPSource.m | 11 ----------- UI/WebServerResources/UIxMailEditor.js | 6 ------ 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.m b/SoObjects/Contacts/SOGoContactLDAPFolder.m index b7d9cdfb9..3e28d9230 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.m +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.m @@ -24,7 +24,6 @@ #import #import #import -#import #import #import @@ -188,10 +187,8 @@ NSEnumerator *oldRecords; NSDictionary *oldRecord; NSMutableDictionary *newRecord; - NSString *data, *contactInfo; - NSUserDefaults *ud; + NSString *data; - ud = [NSUserDefaults standardUserDefaults]; newRecords = [[NSMutableArray alloc] initWithCapacity: [records count]]; [newRecords autorelease]; @@ -240,13 +237,6 @@ data = @""; [newRecord setObject: data forKey: @"phone"]; - contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"]; - if ([contactInfo length] > 0) { - data = [oldRecord objectForKey: contactInfo]; - if ([data length] > 0) - [newRecord setObject: data forKey: @"contactInfo"]; - } - [newRecords addObject: newRecord]; oldRecord = [oldRecords nextObject]; } diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index 4f7ed3b6a..dfc37d341 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -23,7 +23,6 @@ #import #import #import -#import #import #import @@ -395,12 +394,8 @@ static int sizeLimit; - (NSArray *) _searchAttributes { - NSUserDefaults *ud; - NSString *contactInfo; - if (!searchAttributes) { - ud = [NSUserDefaults standardUserDefaults]; searchAttributes = [NSMutableArray new]; if (CNField) [searchAttributes addObject: CNField]; @@ -409,12 +404,6 @@ static int sizeLimit; [searchAttributes addObjectsFromArray: mailFields]; [searchAttributes addObjectsFromArray: [self _contraintsFields]]; [searchAttributes addObjectsFromArray: commonSearchFields]; - - // Add SOGoLDAPContactInfoAttribute from user defaults - contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"]; - if ([contactInfo length] > 0 && - ![searchAttributes containsObject: contactInfo]) - [searchAttributes addObject: contactInfo]; } return searchAttributes; diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index ba924ea1f..64b970e37 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -437,12 +437,6 @@ function performSearchCallback(http) { list.appendChild(node); node.uid = contact["c_uid"]; node.appendChild(document.createTextNode(completeEmail)); - log($H(contact).inspect() + ""); - if (contact["contactInfo"]) { - var info = new Element('span').update(contact['contactInfo']); - node.appendChild(info); - log ("info = " + contact['contactInfo']); - } $(node).observe("mousedown", onAddressResultClick); } From 44c1795d1236c1802bf79f573372259df425a536 Mon Sep 17 00:00:00 2001 From: C Robert Date: Mon, 29 Sep 2008 21:20:38 +0000 Subject: [PATCH 3/7] Added signature placement support for other languages Monotone-Parent: e8f4e2f61f45b6dd1478f6cd53e4f2528bf7c047 Monotone-Revision: a38e7db24accc932b88afb2f7b8fb6717617e957 Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-29T21:20:38 Monotone-Branch: ca.inverse.sogo --- .../SOGoMailDutchReply.html | 8 +++++++- .../SOGoMailDutchReply.wod | 18 ++++++++++++++++++ .../SOGoMailFrenchReply.html | 8 +++++++- .../SOGoMailFrenchReply.wod | 18 ++++++++++++++++++ .../SOGoMailGermanReply.html | 8 +++++++- .../SOGoMailGermanReply.wod | 18 ++++++++++++++++++ .../SOGoMailItalianReply.html | 8 +++++++- .../SOGoMailItalianReply.wod | 18 ++++++++++++++++++ .../SOGoMailSpanishReply.html | 8 +++++++- .../SOGoMailSpanishReply.wod | 18 ++++++++++++++++++ 10 files changed, 125 insertions(+), 5 deletions(-) diff --git a/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.html b/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.html index 7d34187be..e4e5dc000 100644 --- a/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.html +++ b/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.html @@ -1,3 +1,8 @@ +<#signaturePlacementOnTop> + + +<#signature/> + <#outlookMode>-------- Original Message -------- Subject: <#subject/> Date: <#date/> @@ -8,4 +13,5 @@ From: <#from/> <#messageBody/> -<#signature/> + +<#signaturePlacementOnBottom><#signature/> diff --git a/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.wod b/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.wod index 0df01066f..df3789cc3 100644 --- a/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.wod +++ b/SoObjects/Mailer/SOGoMailDutchReply.wo/SOGoMailDutchReply.wod @@ -81,3 +81,21 @@ signature: WOString { value = signature; escapeHTML = NO; } + +replyPlacementOnTop: WOConditional { + condition = replyPlacementOnTop; +} + +replyPlacementOnBottom: WOConditional { + condition = replyPlacementOnTop; + negate = YES; +} + +signaturePlacementOnTop: WOConditional { + condition = signaturePlacementOnTop; +} + +signaturePlacementOnBottom: WOConditional { + condition = signaturePlacementOnTop; + negate = YES; +} diff --git a/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.html b/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.html index 660cd3213..177f36d57 100644 --- a/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.html +++ b/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.html @@ -1,3 +1,8 @@ +<#signaturePlacementOnTop> + + +<#signature/> + <#outlookMode>-------- Message original -------- Sujet: <#subject/> Date: <#date/> @@ -8,4 +13,5 @@ De: <#from/> <#messageBody/> -<#signature/> + +<#signaturePlacementOnBottom><#signature/> diff --git a/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.wod b/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.wod index 0df01066f..df3789cc3 100644 --- a/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.wod +++ b/SoObjects/Mailer/SOGoMailFrenchReply.wo/SOGoMailFrenchReply.wod @@ -81,3 +81,21 @@ signature: WOString { value = signature; escapeHTML = NO; } + +replyPlacementOnTop: WOConditional { + condition = replyPlacementOnTop; +} + +replyPlacementOnBottom: WOConditional { + condition = replyPlacementOnTop; + negate = YES; +} + +signaturePlacementOnTop: WOConditional { + condition = signaturePlacementOnTop; +} + +signaturePlacementOnBottom: WOConditional { + condition = signaturePlacementOnTop; + negate = YES; +} diff --git a/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.html b/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.html index e22ebbc1b..205145b8d 100644 --- a/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.html +++ b/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.html @@ -1,3 +1,8 @@ +<#signaturePlacementOnTop> + + +<#signature/> + <#outlookMode>-------- Original E-Mail -------- Betreff: <#subject/> Datum: <#date/> @@ -8,4 +13,5 @@ Sender: <#from/> <#messageBody/> -<#signature/> + +<#signaturePlacementOnBottom><#signature/> diff --git a/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.wod b/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.wod index 0df01066f..df3789cc3 100644 --- a/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.wod +++ b/SoObjects/Mailer/SOGoMailGermanReply.wo/SOGoMailGermanReply.wod @@ -81,3 +81,21 @@ signature: WOString { value = signature; escapeHTML = NO; } + +replyPlacementOnTop: WOConditional { + condition = replyPlacementOnTop; +} + +replyPlacementOnBottom: WOConditional { + condition = replyPlacementOnTop; + negate = YES; +} + +signaturePlacementOnTop: WOConditional { + condition = signaturePlacementOnTop; +} + +signaturePlacementOnBottom: WOConditional { + condition = signaturePlacementOnTop; + negate = YES; +} diff --git a/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.html b/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.html index e5e96b359..2265ebb3c 100644 --- a/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.html +++ b/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.html @@ -1,3 +1,8 @@ +<#signaturePlacementOnTop> + + +<#signature/> + <#outlookMode>-------- Messaggio originale -------- Oggetto: <#subject/> Data: <#date/> @@ -8,4 +13,5 @@ Da: <#from/> <#messageBody/> -<#signature/> + +<#signaturePlacementOnBottom><#signature/> diff --git a/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.wod b/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.wod index 0df01066f..df3789cc3 100644 --- a/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.wod +++ b/SoObjects/Mailer/SOGoMailItalianReply.wo/SOGoMailItalianReply.wod @@ -81,3 +81,21 @@ signature: WOString { value = signature; escapeHTML = NO; } + +replyPlacementOnTop: WOConditional { + condition = replyPlacementOnTop; +} + +replyPlacementOnBottom: WOConditional { + condition = replyPlacementOnTop; + negate = YES; +} + +signaturePlacementOnTop: WOConditional { + condition = signaturePlacementOnTop; +} + +signaturePlacementOnBottom: WOConditional { + condition = signaturePlacementOnTop; + negate = YES; +} diff --git a/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.html b/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.html index 7d34187be..e4e5dc000 100644 --- a/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.html +++ b/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.html @@ -1,3 +1,8 @@ +<#signaturePlacementOnTop> + + +<#signature/> + <#outlookMode>-------- Original Message -------- Subject: <#subject/> Date: <#date/> @@ -8,4 +13,5 @@ From: <#from/> <#messageBody/> -<#signature/> + +<#signaturePlacementOnBottom><#signature/> diff --git a/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.wod b/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.wod index 0df01066f..df3789cc3 100644 --- a/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.wod +++ b/SoObjects/Mailer/SOGoMailSpanishReply.wo/SOGoMailSpanishReply.wod @@ -81,3 +81,21 @@ signature: WOString { value = signature; escapeHTML = NO; } + +replyPlacementOnTop: WOConditional { + condition = replyPlacementOnTop; +} + +replyPlacementOnBottom: WOConditional { + condition = replyPlacementOnTop; + negate = YES; +} + +signaturePlacementOnTop: WOConditional { + condition = signaturePlacementOnTop; +} + +signaturePlacementOnBottom: WOConditional { + condition = signaturePlacementOnTop; + negate = YES; +} From db936bf021455c58c665a5302f455fa52ecf92cb Mon Sep 17 00:00:00 2001 From: C Robert Date: Mon, 29 Sep 2008 22:01:44 +0000 Subject: [PATCH 4/7] Disabled textarea scrolling when signature is on top. Monotone-Parent: a38e7db24accc932b88afb2f7b8fb6717617e957 Monotone-Revision: 08b02518bde16e0b0865b5640688f3386eefa918 Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-29T22:01:44 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/UIxMailEditor.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index c11fdbda4..a0cab55a0 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -539,7 +539,9 @@ function initMailEditor() { var sigLimit = textContent.lastIndexOf("--"); if (sigLimit > -1) signatureLength = (textContent.length - sigLimit); - textarea.scrollTop = textarea.scrollHeight; + if ( userDefaults["SignaturePlacement"] != "above" ) { + textarea.scrollTop = textarea.scrollHeight; + } textarea.observe("focus", onTextFirstFocus); textarea.observe("focus", onTextFocus); // textarea.observe("contextmenu", onTextContextMenu); From 4b4a8d344641e398ab7093afa68a6653c78c6036 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 30 Sep 2008 13:10:15 +0000 Subject: [PATCH 5/7] Corrige un bug dans le scroll du mailEditor Monotone-Parent: 08b02518bde16e0b0865b5640688f3386eefa918 Monotone-Revision: da4549a652b63b86055b1d36eb59d91375871786 Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-30T13:10:15 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/MailerUI.js | 34 ++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index ee396fffe..4dd368f8e 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -1830,6 +1830,34 @@ function onLabelMenuPrepareVisibility() { lis[0].addClassName("_chosen"); } + +function saveAs() { + saveSelectedMessages(); + preventDefault(event); +} + +function saveSelectedMessages(sender) { + var messageList = $("messageList").down("TBODY"); + var rows = messageList.getSelectedNodes(); + var uids = new Array(); // message IDs + var paths = new Array(); // row IDs + + if (rows.length > 0) { + for (var i = 0; i < rows.length; i++) { + var uid = rows[i].readAttribute("id").substr(4); + var path = Mailer.currentMailbox + "/" + uid; + uids.push(uid); + paths.push(path); + } + var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/saveMessages"; + window.open(url+"?id="+uids+"&uid="+uids+"&mailbox="+Mailer.currentMailbox+"&path="+paths); + } + else + window.alert(labels["Please select a message."]); + + return false; +} + function getMenus() { var menus = {} menus["accountIconMenu"] = new Array(null, null, onMenuCreateFolder, null, @@ -1857,14 +1885,14 @@ function getMenus() { onMenuForwardMessage, null, "-", "moveMailboxMenu", "copyMailboxMenu", "label-menu", - "mark-menu", "-", null, + "mark-menu", "-", saveAs, onMenuViewMessageSource, null, null, onMenuDeleteMessage); menus["messagesListMenu"] = new Array(onMenuForwardMessage, "-", "moveMailboxMenu", "copyMailboxMenu", "label-menu", "mark-menu", "-", - null, null, + saveAs, null, onMenuDeleteMessage); menus["imageMenu"] = new Array(saveImage); menus["messageContentMenu"] = new Array(onMenuReplyToSender, @@ -1874,7 +1902,7 @@ function getMenus() { "copyMailboxMenu", "-", "label-menu", "mark-menu", "-", - null, onMenuViewMessageSource, + saveAs, onMenuViewMessageSource, null, onPrintCurrentMessage, onMenuDeleteMessage); menus["folderTypeMenu"] = new Array(onMenuChangeToSentFolder, From d228e96a78d0ae73e1fb9058b9c875301d4e9cb0 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 30 Sep 2008 13:42:48 +0000 Subject: [PATCH 6/7] See ChangeLog Monotone-Parent: da4549a652b63b86055b1d36eb59d91375871786 Monotone-Revision: 694484559aed659a4395cabbbbf946966b25ff4e Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-30T13:42:48 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 16 +++ SoObjects/Mailer/SOGoDraftsFolder.m | 11 +- SoObjects/Mailer/SOGoMailFolder.h | 5 + SoObjects/Mailer/SOGoMailFolder.m | 134 +++++++++++++++++++-- UI/MailerUI/UIxMailFolderActions.h | 1 + UI/MailerUI/UIxMailFolderActions.m | 27 +++++ UI/MailerUI/product.plist | 5 + UI/Templates/MailerUI/UIxMailMainFrame.wox | 1 + UI/WebServerResources/UIxMailEditor.js | 2 +- 9 files changed, 179 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1fff3ae3f..9e3a17a64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-09-30 Cyril Robert + + * SoObjects/Mailer/SOGoDraftsFolder.m + Moved userSpoolFolderPath method to SOGoMailFolder.m + * SoObjects/Mailer/SOGoMailFolder.h + * SoObjects/Mailer/SOGoMailFolder.m + Added userSpoolFolderPath from SOGoDraftsFolder + Added archiveUIDs method to create an archive from email uids + * UI/MailerUI/UIxMailFolderActions.h + * UI/MailerUI/UIxMailFolderActions.m + Added saveMessagesAction method to handle the /saveMessages call + * UI/MailerUI/product.plist + Added a definition for saveMessages + + + 2008-09-28 Ludovic Marcotte * Modified the following files: diff --git a/SoObjects/Mailer/SOGoDraftsFolder.m b/SoObjects/Mailer/SOGoDraftsFolder.m index f305c2169..47078e920 100644 --- a/SoObjects/Mailer/SOGoDraftsFolder.m +++ b/SoObjects/Mailer/SOGoDraftsFolder.m @@ -47,7 +47,7 @@ static unsigned int newCount; ud = [NSUserDefaults standardUserDefaults]; spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"]; if (![spoolFolder length]) - spoolFolder = @"/tmp/"; + spoolFolder = @"/tmp/"; [spoolFolder retain]; NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder); @@ -102,14 +102,5 @@ static unsigned int newCount; return YES; } -- (NSString *) userSpoolFolderPath -{ - NSString *login; - - login = [[context activeUser] login]; - - return [NSString stringWithFormat: @"%@/%@", - spoolFolder, login]; -} @end diff --git a/SoObjects/Mailer/SOGoMailFolder.h b/SoObjects/Mailer/SOGoMailFolder.h index 839a36084..eba89a3fa 100644 --- a/SoObjects/Mailer/SOGoMailFolder.h +++ b/SoObjects/Mailer/SOGoMailFolder.h @@ -24,6 +24,7 @@ #include #import +#import /* SOGoMailFolder @@ -55,6 +56,7 @@ typedef enum { /* messages */ - (NSException *) deleteUIDs: (NSArray *) uids inContext: (id) context; +- (WOResponse *) archiveUIDs: (NSArray *) uids inContext: (id) context; - (NSArray *) fetchUIDsMatchingQualifier: (id)_q sortOrdering: (id) _so; - (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts; @@ -81,6 +83,9 @@ typedef enum { - (NSArray *) allFolderPaths; - (NSArray *) allFolderURLs; +- (NSString *) userSpoolFolderPath; +- (BOOL) ensureSpoolFolderPath; + @end @interface SOGoSpecialMailFolder : SOGoMailFolder diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 6925e92d5..952d0bbae 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -23,13 +23,16 @@ #import #import #import +#import #import #import +#import #import #import #import #import +#import #import #import @@ -51,6 +54,8 @@ static BOOL aclUsernamesAreQuoted = NO; /* http://www.tools.ietf.org/wg/imapext/draft-ietf-imapext-acl/ */ static BOOL aclConformsToIMAPExt = NO; +static NSString *spoolFolder = nil; + @interface NGImap4Connection (PrivateMethods) - (NSString *) imap4FolderNameForURL: (NSURL *) url; @@ -65,19 +70,29 @@ static BOOL aclConformsToIMAPExt = NO; NSString *aclStyleStr; if (aclStyle == undefined) - { - ud = [NSUserDefaults standardUserDefaults]; - aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"]; - if ([aclStyleStr isEqualToString: @"rfc2086"]) - aclStyle = rfc2086; - else - aclStyle = rfc4314; + { + ud = [NSUserDefaults standardUserDefaults]; + aclStyleStr = [ud stringForKey: @"SOGoIMAPAclStyle"]; + if ([aclStyleStr isEqualToString: @"rfc2086"]) + aclStyle = rfc2086; + else + aclStyle = rfc4314; - aclUsernamesAreQuoted - = [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"]; - aclConformsToIMAPExt - = [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"]; - } + aclUsernamesAreQuoted + = [ud boolForKey: @"SOGoIMAPAclUsernamesAreQuoted"]; + aclConformsToIMAPExt + = [ud boolForKey: @"SOGoIMAPAclConformsToIMAPExt"]; + } + + if (!spoolFolder) + { + spoolFolder = [ud stringForKey:@"SOGoMailSpoolPath"]; + if (![spoolFolder length]) + spoolFolder = @"/tmp/"; + [spoolFolder retain]; + + NSLog(@"Note: using SOGo mail spool folder: %@", spoolFolder); + } } + (SOGoIMAPAclStyle) imapAclStyle @@ -302,6 +317,82 @@ static BOOL aclConformsToIMAPExt = NO; return error; } +- (WOResponse *) archiveUIDs: (NSArray *) uids + inContext: (id) localContext +{ + NSException *error; + NSFileManager *fm; + NSString *spoolPath, *fileName; + NSDictionary *msgs; + NSArray *messages; + NSData *content, *zipContent; + NSTask *zipTask; + NSMutableArray *zipTaskArguments; + WOResponse *response; + int i; + + spoolPath = [self userSpoolFolderPath]; + if ( ![self ensureSpoolFolderPath] ) { + error = [NSException exceptionWithHTTPStatus: 500 + reason: @"spoolFolderPath doesn't exist"]; + return (WOResponse *)error; + } + + fm = [NSFileManager defaultManager]; + if ( ![fm fileExistsAtPath: @"/usr/bin/zip"] ) { + error = [NSException exceptionWithHTTPStatus: 500 + reason: @"zip not available"]; + return (WOResponse *)error; + } + + zipTask = [[NSTask alloc] init]; + [zipTask setCurrentDirectoryPath: spoolPath]; + [zipTask setLaunchPath: @"/usr/bin/zip"]; + + zipTaskArguments = [NSMutableArray arrayWithObjects: nil]; + [zipTaskArguments addObject: @"SavedMessages.zip"]; + + msgs = (NSDictionary *)[self fetchUIDs: uids + parts: [NSArray arrayWithObject: @"RFC822"]]; + messages = [[msgs objectForKey: @"fetch"] retain]; + + for (i = 0; i < [messages count]; i++) { + content = [[messages objectAtIndex: i] objectForKey: @"message"]; + + [content writeToFile: + [NSString stringWithFormat:@"%@/%d.eml", spoolPath, [uids objectAtIndex: i]] + atomically: YES]; + + [zipTaskArguments addObject: + [NSString stringWithFormat:@"%d.eml", [uids objectAtIndex: i]]]; + } + + [zipTask setArguments: zipTaskArguments]; + [zipTask launch]; + [zipTask waitUntilExit]; + + [zipTask release]; + + zipContent = [[NSData alloc] initWithContentsOfFile: + [NSString stringWithFormat: @"%@/SavedMessages.zip", spoolPath]]; + + for(i = 0; i < [zipTaskArguments count]; i++) { + fileName = [zipTaskArguments objectAtIndex: i]; + [fm removeFileAtPath: + [NSString stringWithFormat: @"%@/%@", spoolPath, fileName] handler: nil]; + } + + response = [[WOResponse alloc] init]; + [response autorelease]; + [response setHeader: @"application/zip" forKey:@"content-type"]; + [response setHeader: @"attachment;filename=SavedMessages.zip" forKey: @"Content-Disposition"]; + [response setContent: zipContent]; + + [zipContent release]; + + return response; +} + - (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so { @@ -891,6 +982,25 @@ static BOOL aclConformsToIMAPExt = NO; return [userURL absoluteString]; } +- (NSString *) userSpoolFolderPath +{ + NSString *login; + + login = [[context activeUser] login]; + + return [NSString stringWithFormat: @"%@/%@", + spoolFolder, login]; +} + +- (BOOL) ensureSpoolFolderPath +{ + NSFileManager *fm; + + fm = [NSFileManager defaultManager]; + + return ([fm createDirectoriesAtPath: [self userSpoolFolderPath] attributes:nil]); +} + @end /* SOGoMailFolder */ @implementation SOGoSpecialMailFolder diff --git a/UI/MailerUI/UIxMailFolderActions.h b/UI/MailerUI/UIxMailFolderActions.h index 51e3dc669..594bff8c9 100644 --- a/UI/MailerUI/UIxMailFolderActions.h +++ b/UI/MailerUI/UIxMailFolderActions.h @@ -33,6 +33,7 @@ - (WOResponse *) renameFolderAction; - (WOResponse *) deleteFolderAction; - (WOResponse *) deleteMessagesAction; +- (WOResponse *) saveMessagesAction; - (WOResponse *) expungeAction; - (WOResponse *) emptyTrashAction; - (WOResponse *) subscribeAction; diff --git a/UI/MailerUI/UIxMailFolderActions.m b/UI/MailerUI/UIxMailFolderActions.m index 6e7f2b020..c7237b0d5 100644 --- a/UI/MailerUI/UIxMailFolderActions.m +++ b/UI/MailerUI/UIxMailFolderActions.m @@ -209,6 +209,33 @@ return response; } +- (WOResponse *) saveMessagesAction +{ + SOGoMailFolder *co; + WOResponse *response; + NSArray *uids; + NSString *value; + + co = [self clientObject]; + value = [[context request] formValueForKey: @"uid"]; + response = nil; + + if ([value length] > 0) + { + uids = [value componentsSeparatedByString: @","]; + response = [co archiveUIDs: uids inContext: context]; + if (!response) + response = [self responseWith204]; + } + else + { + response = [self responseWithStatus: 500]; + [response appendContentString: @"Missing 'uid' parameter."]; + } + + return response; +} + - (WOResponse *) _setFolderPurpose: (NSString *) purpose { SOGoMailFolder *co; diff --git a/UI/MailerUI/product.plist b/UI/MailerUI/product.plist index 0bc397b63..f759eea14 100644 --- a/UI/MailerUI/product.plist +++ b/UI/MailerUI/product.plist @@ -141,6 +141,11 @@ actionClass = "UIxMailFolderActions"; actionName = "deleteMessages"; }; + saveMessages = { + protectedBy = "View"; + actionClass = "UIxMailFolderActions"; + actionName = "saveMessages"; + }; setAsDraftsFolder = { protectedBy = "View"; actionClass = "UIxMailFolderActions"; diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index fafe9f69f..63f5c1cb7 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -124,6 +124,7 @@
  • +
  • diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index a0cab55a0..8080c1340 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -539,7 +539,7 @@ function initMailEditor() { var sigLimit = textContent.lastIndexOf("--"); if (sigLimit > -1) signatureLength = (textContent.length - sigLimit); - if ( userDefaults["SignaturePlacement"] != "above" ) { + if ( userDefaults["ReplyPlacement"] != "above" ) { textarea.scrollTop = textarea.scrollHeight; } textarea.observe("focus", onTextFirstFocus); From 9e962919538e134e49bd039c802859dc61998cc0 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 30 Sep 2008 15:00:28 +0000 Subject: [PATCH 7/7] Fixed a few bugs & incoherences Monotone-Parent: 694484559aed659a4395cabbbbf946966b25ff4e Monotone-Revision: d44c77e73da2480ce01afa441c8a2705f220ae25 Monotone-Author: crobert@inverse.ca Monotone-Date: 2008-09-30T15:00:28 Monotone-Branch: ca.inverse.sogo --- SoObjects/Mailer/SOGoMailFolder.m | 2 +- UI/WebServerResources/MailerUI.js | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 952d0bbae..a462d3b90 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -354,7 +354,7 @@ static NSString *spoolFolder = nil; msgs = (NSDictionary *)[self fetchUIDs: uids parts: [NSArray arrayWithObject: @"RFC822"]]; - messages = [[msgs objectForKey: @"fetch"] retain]; + messages = [msgs objectForKey: @"fetch"]; for (i = 0; i < [messages count]; i++) { content = [[messages objectAtIndex: i] objectForKey: @"message"]; diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 4dd368f8e..e936a49d8 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -1830,13 +1830,7 @@ function onLabelMenuPrepareVisibility() { lis[0].addClassName("_chosen"); } - -function saveAs() { - saveSelectedMessages(); - preventDefault(event); -} - -function saveSelectedMessages(sender) { +function saveAs(event) { var messageList = $("messageList").down("TBODY"); var rows = messageList.getSelectedNodes(); var uids = new Array(); // message IDs