View Issue Details

IDProjectCategoryView StatusLast Update
0002168SOGoWeb Mailpublic2019-05-03 11:38
Reporterturip Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
PlatformLinuxOSDebianOS Version5 (Lenny)
Product Version2.0.3a 
Target Versionsoon 
Summary0002168: Proper multiple identity support for the LDAPSource
Description

Multiple mail identities for the mail account of the user is a long missing feature of sogo.

I have created a patch, that:

  • Allows SOGOUserSource objects to override the identity associated with the current user.
  • Modified the mail editor UI to support multiple identities and set their settings on the UIxMailEditor page
  • Added proper replyTo support for mails
  • Modified the preferences UI to provie a list of identities available for the main account
  • System warns about incompatibility with Aux mail accounts
  • Removed currentIndex lastIndex madness from UIxMailToSelect component.

I'd kindly ask you to provide comments on this patch and if it seems fine please include it in git.

Note that SQLSource does not implement the interface yet. The patch is aganst the 2.0.3a debian codebase.

Additional Information

The configuration is done via the following defaults:
sogod SOGoMailExtendedLDAPIdentitySettings '{
baseDN = "uid=%U,ou=people,dc=caesar,dc=elte,dc=hu";
filter = "(objectClass=mailIdentity)";
identityBCC = identityBCC;
identityCC = identityCC;
identityConfirmed = identityConfirmed;
identityFromAddress = identityFromAddress;
identityFromName = identityFromName;
identityReplyTo = identityReplyTo;
identitySignature = identitySignature;
identityWeight = identityWeight;
}'

sogod SOGoMailExtendedIdentities YES

The baseDN is the dn under the %U gets replaced with the username and %D gets replaced with the domain the user logs into.

Search is performed under this dn, searching for the filter criteria.

The identity* fields specify the attributes with the given value.

This can be set also on domain level.

This can be used with ldap entries like this:

dn: identityFromAddress=sdsadystem@caesar.elte.hu,uid=tasdurip,ou=People,dc=caesar,dc
=elte,dc=hu
objectClass: top
objectClass: mailIdentity
identityBCC: Caesar rendszergazda <sydsastem@caesar.elte.hu>
identityFromName: Caesar rendszergazda
identityConfirmed: TRUE
identitySignature: Caesar rendszergazda stb
identityFromAddress: sydsastem@caesar.elte.hu
identityReplyTo: norepdsly@caesar.elte.hu
identityWeight: 10

identityFromAddress=turip@cdsadaesar.elte.hu,uid=tasdurip,ou=People,dc=caesar,dc=
elte,dc=hu
objectClass: top
objectClass: mailIdentity
identityFromName: Turi Peter
identityConfirmed: TRUE
identitySignature:: UGxhc3RpYyBleGlzdGFuY2Ug
identityFromAddress: turiasddsap@caedsadsasar.elte.hu
identityCC: Test <testsasd@casddsadaesar.elte.hu>
identityWeight: 1

The following schema can be used to store these objects (the oids are registered and reserved for this system):

dn: cn={4}elte
objectClass: olcSchemaConfig
cn: {4}elte
olcObjectIdentifier: {0}ISO 1
olcObjectIdentifier: {1}ORG ISO:3
olcObjectIdentifier: {2}DOD ORG:6
olcObjectIdentifier: {3}INTERNET DOD:1
olcObjectIdentifier: {4}PRIVATE INTERNET:4
olcObjectIdentifier: {5}ENTERPRISE PRIVATE:1
olcObjectIdentifier: {6}ELTE ENTERPRISE:6807
olcObjectIdentifier: {7}ELTELDAP ELTE:1
olcObjectIdentifier: {8}ELTEAttr ELTELDAP:1
olcObjectIdentifier: {9}ELTEClass ELTELDAP:2
olcObjectIdentifier: {10}ELTESyntax ELTELDAP:3
olcAttributeTypes: {18}( ELTEAttr:1001 NAME 'identityCC' DESC 'Mail addresses to include in the cc list for this identity' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {19}( ELTEAttr:1002 NAME 'identityBCC' DESC 'Mail addresses to include in the bcc list for this identity' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {20}( ELTEAttr:1003 NAME 'identityReplyTo' DESC 'Mail addresses to send the reply to' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
olcAttributeTypes: {21}( ELTEAttr:1004 NAME 'identityFromAddress' DESC 'Email address for this identity' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
olcAttributeTypes: {22}( ELTEAttr:1005 NAME 'identityFromName' DESC 'Display name for the given from field' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
olcAttributeTypes: {23}( ELTEAttr:1006 NAME 'identitySignature' DESC 'User signature' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
olcAttributeTypes: {24}( ELTEAttr:1007 NAME 'identityConfirmed' DESC 'Is the given identity enabled to the user?' EQUALITY BooleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
olcAttributeTypes: {25}( ELTEAttr:1008 NAME 'identityWeight' DESC 'Ordering for the identities' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
olcObjectClasses: {9}( ELTEClass:1000 NAME 'mailIdentity' DESC 'Mail identity of the given user' SUP top STRUCTURAL MUST identityFromAddress MAY ( identityCC $ identityBCC $ identityReplyTo $ identityFromName $ identitySignature $ identityConfirmed $ identityWeight ) )

TagsNo tags attached.

Activities

2013-01-09 08:54

 

sogo-2.0.3a-multi-identity.patch (42,009 bytes)   
diff -ur sogo-2.0.3a/UI/MailerUI/English.lproj/Localizable.strings sogo-2.0.3a-my/UI/MailerUI/English.lproj/Localizable.strings
--- sogo-2.0.3a/UI/MailerUI/English.lproj/Localizable.strings	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/MailerUI/English.lproj/Localizable.strings	2013-01-07 14:38:01.000000000 +0100
@@ -106,6 +106,7 @@
 "to"            = "To";
 "cc"            = "Cc";
 "bcc"           = "Bcc";
+"replyTo"	= "Reply to";
 
 "Edit Draft..." = "Edit Draft...";
 "Load Images" = "Load Images";
diff -ur sogo-2.0.3a/UI/MailerUI/Hungarian.lproj/Localizable.strings sogo-2.0.3a-my/UI/MailerUI/Hungarian.lproj/Localizable.strings
--- sogo-2.0.3a/UI/MailerUI/Hungarian.lproj/Localizable.strings	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/MailerUI/Hungarian.lproj/Localizable.strings	2013-01-08 12:05:29.000000000 +0100
@@ -106,6 +106,7 @@
 "to"            = "Címzett";
 "cc"            = "Másolat";
 "bcc"           = "Titkos másolat";
+"replyTo"	= "Válaszcím";
 
 "Edit Draft..." = "Piszkozat szerkesztése...";
 "Load Images" = "Képek betöltése";
diff -ur sogo-2.0.3a/UI/MailerUI/UIxMailEditor.m sogo-2.0.3a-my/UI/MailerUI/UIxMailEditor.m
--- sogo-2.0.3a/UI/MailerUI/UIxMailEditor.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/MailerUI/UIxMailEditor.m	2013-01-09 09:19:16.000000000 +0100
@@ -72,6 +72,7 @@
   NSArray  *to;
   NSArray  *cc;
   NSArray  *bcc;
+  NSArray  *replyTo;
   NSString *subject;
   NSString *sourceUID;
   NSString *sourceFolder;
@@ -133,6 +134,7 @@
   [to release];
   [cc release];
   [bcc release];
+  [replyTo release];
   [sourceUID release];
   [sourceFolder release];
   [attachmentName release];
@@ -153,6 +155,11 @@
   return item;
 }
 
+- (NSString *) userIdentities
+{
+      return [[[context activeUser] allIdentities] jsonRepresentation ];
+}
+
 - (NSArray *) priorityClasses
 {
   static NSArray *priorities = nil;
@@ -249,13 +256,24 @@
   return from;
 }
 
-- (NSString *) replyTo
+- (NSArray *) replyTo
 {
-  SOGoUserDefaults *ud;
+  NSString * rv;
 
-  ud = [[context activeUser] userDefaults];
+  if (!replyTo)
+  {
 
-  return [ud mailReplyTo];
+	  NSDictionary *identity;
+	  identity = [[context activeUser] primaryIdentity];
+	  rv = [identity objectForKey:@"replyTo"];
+	  if (rv != nil)
+	  {
+		  replyTo = [NSArray arrayWithObjects: rv, nil];
+		  [replyTo retain];
+		  return replyTo;
+	  }
+  }
+  return replyTo;
 }
 
 - (void) setSubject: (NSString *) newSubject
@@ -275,6 +293,17 @@
 
 - (NSString *) text
 {
+  NSString * rv;
+  if (!text)
+  {
+	  NSDictionary *identity;
+	  identity = [[context activeUser] primaryIdentity];
+	  rv = [identity objectForKey:@"signature"];
+	  if (rv != nil)
+	  {
+	  	text = [NSMutableString stringWithFormat: "-- \n%@", rv];
+	  }
+  }
   return text;
 }
 
@@ -311,6 +340,12 @@
 
 - (NSArray *) to
 {
+  if (to == nil)
+  {
+  	// This forces insertion of an empty to field
+  	to = [NSArray arrayWithObjects: @"", nil];
+	[to retain];
+  }
   return to;
 }
 
@@ -324,6 +359,20 @@
 
 - (NSArray *) cc
 {
+  NSArray * idCC;
+  NSDictionary *identity;
+  // Return the CC list from the default identity if none are set
+  if (cc == nil)
+  {
+    identity = [[context activeUser] primaryIdentity];
+    idCC = [identity objectForKey:@"cc"];
+    if (idCC != nil)
+    {
+      cc=idCC;
+      [cc retain];
+    }
+  }
+
   return cc;
 }
 
@@ -337,6 +386,21 @@
 
 - (NSArray *) bcc
 {
+  NSArray * idBCC;
+  NSDictionary *identity;
+  // Return the CC list from the default identity if none are set
+  if (bcc == nil)
+  {
+    identity = [[context activeUser] primaryIdentity];
+    idBCC = [identity objectForKey:@"bcc"];
+    if (idBCC != nil)
+    {
+      bcc = idBCC;
+      [bcc retain];
+    }
+  }
+
+
   return bcc;
 }
 
diff -ur sogo-2.0.3a/UI/MailerUI/UIxMailToSelection.m sogo-2.0.3a-my/UI/MailerUI/UIxMailToSelection.m
--- sogo-2.0.3a/UI/MailerUI/UIxMailToSelection.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/MailerUI/UIxMailToSelection.m	2013-01-08 11:28:36.000000000 +0100
@@ -44,6 +44,7 @@
   to="to"
   cc="cc"
   bcc="bcc"
+  replyTo="replyTo"
   />
 */
 
@@ -54,6 +55,7 @@
   NSArray *to;
   NSArray *cc;
   NSArray *bcc;
+  NSArray *replyTo;
   id      item;
   id      address;
   NSArray *addressList;
@@ -66,6 +68,8 @@
 - (NSArray *) cc;
 - (void) setBcc: (NSArray *) _bcc;
 - (NSArray *) bcc;
+- (void) setReplyTo: (NSArray *) _replyTo;
+- (NSArray *) replyTo;
 
 - (void) getAddressesFromFormValues: (NSDictionary *) _dict;
 - (NSString *) getIndexFromIdentifier: (NSString *) _identifier;
@@ -82,7 +86,7 @@
   if (!didInit)
     {
       didInit = YES;
-      headers = [[NSArray alloc] initWithObjects: @"to", @"cc", @"bcc", nil];
+      headers = [[NSArray alloc] initWithObjects: @"to", @"cc", @"bcc", @"replyTo", nil];
     }
 }
 
@@ -99,6 +103,7 @@
   [to          release];
   [cc          release];
   [bcc         release];
+  [replyTo     release];
   [item        release];
   [address     release];
   [addressList release];
@@ -166,6 +171,18 @@
   return address;
 }
 
+- (void) setReplyTo: (NSArray *) _replyTo
+{
+  ASSIGN(replyTo,_replyTo);
+}
+
+- (NSArray *) replyTo
+{
+  return replyTo;
+}
+
+
+
 - (void) setItem: (id) _item
 {
   ASSIGN (item, _item);
@@ -211,6 +228,8 @@
     return @"to";
   else if (addressList == cc)
     return @"cc";
+  else if (addressList == replyTo)
+    return @"replyTo";
 
   return @"bcc";
 }
@@ -264,7 +283,7 @@
 
 - (void) getAddressesFromFormValues: (NSDictionary *) _dict
 {
-  NSMutableArray *rawTo, *rawCc, *rawBcc;
+  NSMutableArray *rawTo, *rawCc, *rawBcc, *rawReplyTo;
   NSString *idx, *popupKey, *popupValue;
   NSArray *keys;
   unsigned i, count;
@@ -273,6 +292,7 @@
   rawTo  = [NSMutableArray arrayWithCapacity:4];
   rawCc  = [NSMutableArray arrayWithCapacity:4];
   rawBcc = [NSMutableArray arrayWithCapacity:2];
+  rawReplyTo = [NSMutableArray arrayWithCapacity:2];
   
   keys  = [_dict allKeys];
   count = [keys count];
@@ -291,6 +311,8 @@
 	    [self _fillAddresses: rawTo withObject: addr];
 	  else if([popupValue isEqualToString:@"1"])
 	    [self _fillAddresses: rawCc withObject: addr];
+	  else if([popupValue isEqualToString:@"3"])
+	    [self _fillAddresses: rawReplyTo withObject: addr];
 	  else
 	    [self _fillAddresses: rawBcc withObject: addr];
 	}
@@ -299,6 +321,7 @@
   [self setTo: rawTo];
   [self setCc: rawCc];
   [self setBcc: rawBcc];
+  [self setReplyTo: rawReplyTo];
 }
 
 - (NSString *) getIndexFromIdentifier: (NSString *) _identifier
@@ -330,7 +353,7 @@
 
 - (int) addressCount
 {
-  return [to count] + [cc count] + [bcc count];
+  return [to count] + [cc count] + [bcc count] + [replyTo count];
 }
 
 @end /* UIxMailToSelection */
diff -ur sogo-2.0.3a/UI/PreferencesUI/UIxPreferences.m sogo-2.0.3a-my/UI/PreferencesUI/UIxPreferences.m
--- sogo-2.0.3a/UI/PreferencesUI/UIxPreferences.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/PreferencesUI/UIxPreferences.m	2013-01-08 14:13:06.000000000 +0100
@@ -1566,6 +1566,16 @@
   return [accounts jsonRepresentation];
 }
 
+- (BOOL) hasExtendedIdentities
+{
+	return [user hasExtendedIdentities];
+}
+
+- (NSArray *) userIdentityList
+{
+	return [user allIdentities];
+}
+
 - (NSString *) mailCustomFromEnabled
 {
   return (mailCustomFromEnabled ? @"true" : @"false");
diff -ur sogo-2.0.3a/UI/Templates/MailerUI/UIxMailEditor.wox sogo-2.0.3a-my/UI/Templates/MailerUI/UIxMailEditor.wox
--- sogo-2.0.3a/UI/Templates/MailerUI/UIxMailEditor.wox	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/Templates/MailerUI/UIxMailEditor.wox	2013-01-08 09:02:47.000000000 +0100
@@ -17,6 +17,7 @@
     var sourceUID = <var:string value="sourceUID"/>;
     var sourceFolder = '<var:string value="sourceFolder" const:escapeHTML="NO"/>';
     var localeCode = '<var:string value="localeCode"/>';
+    var userIdentities = eval('<var:string value="userIdentities" const:escapeHTML="NO"/>');
   </script>
   <div class="popupMenu" id="contactsMenu">
     <ul><!-- space --></ul>
@@ -124,7 +125,7 @@
 	/><br />
       <div>
 	<var:component className="UIxMailToSelection"
-	  to="to" cc="cc" bcc="bcc" />
+	  to="to" cc="cc" bcc="bcc" replyTo="replyTo"/>
       </div>
       <div class="addressListElement" id="subjectRow"
 	><span class="headerField"><var:string label:value="Subject"
diff -ur sogo-2.0.3a/UI/Templates/MailerUI/UIxMailToSelection.wox sogo-2.0.3a-my/UI/Templates/MailerUI/UIxMailToSelection.wox
--- sogo-2.0.3a/UI/Templates/MailerUI/UIxMailToSelection.wox	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/Templates/MailerUI/UIxMailToSelection.wox	2013-01-08 09:47:40.000000000 +0100
@@ -5,9 +5,6 @@
     xmlns:rsrc="OGo:url"
     xmlns:label="OGo:label"
     >
-    <script type="text/javascript">
-      var currentIndex = <var:string value="currentIndex" />;
-    </script>
 
     <div class="addressList">
     <table id="addressList" cellpadding="0" cellspacing="0"
@@ -35,15 +32,16 @@
         </var:foreach>
       </var:foreach>
       <tr class="addressListElement" id="lastRow">
-        <td class="headerField" onclick="fancyAddRow('');">
+        <td class="headerField" onclick="fancyAddRow('', false, true);">
         <var:popup name="currentPopUpId"
+		   id="currentPopUpId"
               list="headers"
               item="item"
               label:displayString="$item"
               />
         </td>
         <td class="headerInput">
-          <span class="headerInput"><input onfocus="fancyAddRow('');"
+          <span class="headerInput"><input onfocus="fancyAddRow('', false, true);"
             readonly="1"
             tabindex="-1"
             type="text"
diff -ur sogo-2.0.3a/UI/Templates/PreferencesUI/UIxPreferences.wox sogo-2.0.3a-my/UI/Templates/PreferencesUI/UIxPreferences.wox
--- sogo-2.0.3a/UI/Templates/PreferencesUI/UIxPreferences.wox	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/Templates/PreferencesUI/UIxPreferences.wox	2013-01-08 15:00:26.000000000 +0100
@@ -293,14 +293,21 @@
                       ><!-- space --></ul
                       ></div>
             <var:if condition="mailAuxiliaryUserAccountsEnabled">
-              <div const:id="mailAccountsToolbar" class="bottomToolbar">
-                <a const:id="mailAccountAdd" class="bottomButton" href="#">
-                  <span><img rsrc:src="add-icon.png" label:title="Add" />
-                </span></a>
-                <a const:id="mailAccountDelete" class="bottomButton" href="#">
-                  <span><img rsrc:src="remove-icon.png" label:title="Delete" />
-                </span></a>
-              </div>
+	      <var:if condition="hasExtendedIdentities">
+	      	<script type="text/javascript">
+			alert('MailAuxiliaryUserAccounts are not compatbile (nor tested) with ExtendedIdentities');
+		</script>
+	      </var:if>
+	      <var:if condition="hasExtendedIdentities" const:negate="YES">
+                <div const:id="mailAccountsToolbar" class="bottomToolbar">
+                  <a const:id="mailAccountAdd" class="bottomButton" href="#">
+                    <span><img rsrc:src="add-icon.png" label:title="Add" />
+                  </span></a>
+                  <a const:id="mailAccountDelete" class="bottomButton" href="#">
+                    <span><img rsrc:src="remove-icon.png" label:title="Delete" />
+                  </span></a>
+                </div>
+	       </var:if>
             </var:if>
             <div id="mailAccountEditor">
               <fieldset const:id="accountInfo">
@@ -329,16 +336,63 @@
               </script>
 
               <fieldset const:id="identityInfo">
-                <dl class="dl-horizontal">
-                  <dt><var:string label:value="Full Name:"/></dt>
-                  <dd><input const:name="fullName" const:id="fullName" type="text" const:value=""/></dd>
-                  <dt><var:string label:value="Email:"/></dt>
-                  <dd><input const:name="email" const:id="email" type="text" const:value=""/></dd>
-                  <dt><var:string label:value="Reply To Email:"/></dt>
-                  <dd><input const:name="replyTo" const:id="replyTo" type="text" autocomplete="off" const:value=""/></dd>
-                  <dt><var:string label:value="Signature:"/></dt>
-                  <dd><span id="actSignature"><!--space --></span></dd>
-                </dl>
+	      	<var:if condition="hasExtendedIdentities">
+			<dl class="dl-horizontal" id="extendedIdentitySettings">
+				<var:foreach list="userIdentityList" item="identity">
+					<dt><var:string label:value="Full Name:"/></dt>
+					<dd><var:string var:value="identity.fullName"/></dd>
+
+
+					<dt><var:string label:value="Email:"/></dt>
+					<dd><var:string var:value="identity.email"/></dd>
+
+
+					<var:if condition="identity.replyTo">
+						<dt><var:string label:value="Reply To Email:"/></dt>
+						<dd><var:string var:value="identity.replyTo"/></dd>
+					</var:if>
+
+					<var:if condition="identity.signature">
+						<dt><var:string label:value="Signature:"/></dt>
+						<dd><var:string var:value="identity.signature"/></dd>
+					</var:if>
+
+					<var:if condition="identity.cc">
+						<dt><var:string label:value="Send copy to:"/></dt>
+						<dd>
+							<var:foreach list="identity.cc" item="addr">
+								<var:string var:value="addr"/>
+							</var:foreach>
+						</dd>
+					</var:if>
+
+					<var:if condition="identity.bcc">
+						<dt><var:string label:value="Send secret copy to:"/></dt>
+						<dd>
+							<var:foreach list="identity.bcc" item="addr">
+								<var:string var:value="addr"/>
+							</var:foreach>
+						</dd>
+					</var:if>
+					<p/>
+				</var:foreach>
+			</dl>
+		</var:if>
+		<script type="text/javascript">
+			var hasExtendedIdentities = <var:string var:value="hasExtendedIdentities"/>;
+		</script>
+	      	<var:if condition="hasExtendedIdentities" const:negate="YES">
+			<dl class="dl-horizontal" id="baseIdentitySettings">
+			  <dt><var:string label:value="Full Name:"/></dt>
+			  <dd><input const:name="fullName" const:id="fullName" type="text" const:value=""/></dd>
+			  <dt><var:string label:value="Email:"/></dt>
+			  <dd><input const:name="email" const:id="email" type="text" const:value=""/></dd>
+			  <dt><var:string label:value="Reply To Email:"/></dt>
+			  <dd><input const:name="replyTo" const:id="replyTo" type="text" autocomplete="off" const:value=""/></dd>
+			  <dt><var:string label:value="Signature:"/></dt>
+			  <dd><span id="actSignature"><!--space --></span></dd>
+			</dl>
+		</var:if>
               </fieldset>
 
               <fieldset const:id="returnReceiptsInfo">
diff -ur sogo-2.0.3a/UI/WebServerResources/UIxMailEditor.js sogo-2.0.3a-my/UI/WebServerResources/UIxMailEditor.js
--- sogo-2.0.3a/UI/WebServerResources/UIxMailEditor.js	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/WebServerResources/UIxMailEditor.js	2013-01-08 15:07:20.000000000 +0100
@@ -35,6 +35,8 @@
             neededOptionValue = 1;
         else if (tag == "bcc")
             neededOptionValue = 2;
+	else if (tag == "replyTo")
+	    neededOptionValue = 3;
 
         var stop = false;
         var counter = 0;
@@ -51,16 +53,59 @@
 
         if (!stop) {
             fancyAddRow("");
-            var row = $("row_" + currentIndex);
+            var row = $("row_" + mailToLastIndex());
             var td = $(row.childNodesWithTag("td")[0]);
             var select = $(td.childNodesWithTag("select")[0]);
             select.value = neededOptionValue;
-            insertContact($("addr_" + currentIndex), contactName, contactEmail);
+            insertContact($("addr_" + mailToLastIndex()), contactName, contactEmail);
             onWindowResize(null);
         }
     }
 }
 
+function removeContact(tag, fullContactName, contactId, contactName, contactEmail)
+{
+	var neededOptionValue;
+        if (tag == "cc")
+            neededOptionValue = 1;
+        else if (tag == "bcc")
+            neededOptionValue = 2;
+	else if (tag == "replyTo")
+	    neededOptionValue = 3;
+	else
+	    console.log("Invalid tag name: ", tag);
+
+
+        var stop = false;
+        var counter = 0;
+        var currentRow = $('row_' + counter);
+	var removeRow = undefined;
+        while (currentRow && !stop) {
+            var currentFlag = $(currentRow.childNodesWithTag("td")[0]).childNodesWithTag("select")[0].value;
+            var currentAddressRaw = $(currentRow.childNodesWithTag("td")[1]).childNodesWithTag("input")[0].value;
+	    var currentAddress = parseMailAddress(currentAddressRaw);
+	    if (
+	    	(currentAddress != undefined) && 
+		(currentAddress.mail == contactEmail) &&
+		(currentFlag == neededOptionValue)
+		)
+	    {
+	    	removeRow = counter;
+		stop = true;
+	    }
+            counter++;
+            currentRow = $('row_' + counter);
+        }
+
+	if (removeRow !== undefined)
+	{
+		counter = removeRow;
+		fancyRemoveRow(counter);
+	}
+
+
+}
+
 function onContactFolderChange(event) {
     initCriteria();
     openContactsFolder(this.value);
@@ -366,7 +411,7 @@
         else {
             // Search for signature starting from bottom
             node = children.getItem(children.count() - 1);
-            while (true) {
+            while (node != null) {
                 var x = node.getPrevious();
                 if (x == null) {
                     break;
@@ -378,6 +423,10 @@
                 node = x;
             }
         }
+	if (node == null)
+	{
+		return; //TODO: Why?! (turip)
+	}
 
         s.selectElement(node);
 
@@ -512,10 +561,164 @@
     
     Event.observe(window, "resize", onWindowResize);
     Event.observe(window, "beforeunload", onMailEditorClose);
-    
+
+    $("fromSelect").observe("change", function() { onFromChange(false); });
+
     onWindowResize.defer();
 }
 
+var oldFromIndex = 0; // As the array is sorted it will always contain the default identity first
+function onFromChange(reset)
+{
+	var newidx = $("fromSelect").value;
+	var id = userIdentities[newidx];
+	var oldId = undefined;
+	console.log("Form change trigger");
+
+	if (oldFromIndex !== undefined)
+	{
+		oldId = userIdentities[oldFromIndex];
+	}
+
+	if (oldId !== undefined)
+	{
+
+	    removeIdentityDestAddresses(oldId.bcc, "bcc");
+	    removeIdentityDestAddresses(oldId.cc, "cc");
+	    removeIdentityDestAddresses([oldId.replyTo], "replyTo");
+	}
+
+	oldFromIndex = newidx;
+
+	console.log("Change ", oldId, "=>", userIdentities[newidx]);
+
+	// Signature hacking
+
+	var composeMode = UserDefaults["SOGoMailComposeMessageType"];
+	// Regexp matches anything with a suffix of -- then nbsp or space times then <br/> \n \r
+	var sigRegexp = /^([\s\S]*)(--(&nbsp;| )*)(<br +\/>|\n|\r)([\s\S]*)$/m;
+	var html = (composeMode == "html");
+
+	var sig;
+	if (id.signature !== undefined)
+	{
+
+		sig = id.signature;
+		sig = "-- \n" + sig;
+	}
+	else
+	{
+		sig = "";
+	}
+
+	if (html)
+		sig = sig.replace("\n", "<br />");
+
+	var txt;
+
+	if (html)
+		txt =  CKEDITOR.instances.text.getData();
+	else
+		txt = $("text").value;
+
+	var match = txt.match(sigRegexp);
+	if (match != null)
+	{
+		txt = match[1];
+	}
+	txt=txt+sig;
+
+	if (html)
+		CKEDITOR.instances.text.setData(txt);
+	else
+		$("text").value = txt;
+
+	// Set BCC fields
+
+	addIdentityDestAddresses(id.bcc, "bcc");
+	addIdentityDestAddresses(id.cc, "cc");
+	addIdentityDestAddresses([id.replyTo], "replyTo"); 
+
+    // TODO: Implement logic that jumps to the first empty To field if such is present or focuses the text area
+}
+
+function parseMailAddress(addr)
+{
+	var mailNormal = /.+@.+\..+/;
+	var found = false;
+	var rv;
+
+	var mailre = /<.+@.+\..+>/;
+	var mail = mailre.exec(addr);
+	if (mail)
+	{
+		rv = {
+			mail: mail[0].substr(1,mail[0].length-2),
+			text: addr.replace(mailre, "").trim()
+		};
+		found = true;
+	}
+	else
+	{
+		if (mailNormal.exec(addr))
+		{
+			rv = {
+				mail: addr,
+				text: ""
+			};
+			found = true;
+		}
+	}
+
+	if (!found)
+	{
+		return undefined;
+	}
+
+	return rv;
+		
+}
+
+function removeIdentityDestAddresses(arr, type)
+{
+    if (arr !== undefined)
+    {
+    	for (var i = 0; i < arr.length; i++)
+	{
+		mparsed = parseMailAddress(arr[i]);
+		if (mparsed !== undefined)
+		{
+			removeContact(type, arr[i], undefined, 
+				mparsed.text,
+				mparsed.mail);
+		}
+	}
+    }
+
+}
+
+
+function addIdentityDestAddresses(arr, type)
+{
+    if (arr !== undefined)
+    {
+    	for (var i = 0; i < arr.length; i++)
+	{
+		mparsed = parseMailAddress(arr[i]);
+		if (mparsed !== undefined)
+		{
+			addContact(type, arr[i], undefined, 
+				mparsed.text,
+				mparsed.mail);
+		}
+
+			
+
+	}
+    }
+
+}
+
 function initializePriorityMenu() {
     var priority = $("priority").value.toUpperCase();
     var priorityMenu = $("priorityMenu").childNodesWithTag("ul")[0];
diff -ur sogo-2.0.3a/UI/WebServerResources/UIxMailToSelection.js sogo-2.0.3a-my/UI/WebServerResources/UIxMailToSelection.js
--- sogo-2.0.3a/UI/WebServerResources/UIxMailToSelection.js	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/WebServerResources/UIxMailToSelection.js	2013-01-08 11:05:21.000000000 +0100
@@ -29,7 +29,12 @@
  * surrounding context to check.
  */
 
-var lastIndex = currentIndex;
+var lastIndex = -1;
+
+function mailToLastIndex()
+{
+	return lastIndex;
+}
 
 function sanitizedCn(cn) {
     var parts;
@@ -47,10 +52,32 @@
 }
 
 function checkAddresses() {
-    alert("addressCount: " + this.getAddressCount() + " currentIndex: " + currentIndex + " lastIndex: " + lastIndex);
+    alert("addressCount: " + this.getAddressCount() + " lastIndex: " + lastIndex);
+}
+
+function fancyRemoveRow(id)
+{
+	var counter = id;
+	var currentRow = $('row_' + counter);
+	currentRow.remove();
+	counter++;
+	currentRow = $('row_'+counter);
+	while (currentRow)
+	{
+		currentRow.setAttribute("id", "row_"+(counter-1));
+		var addr = $('addr_'+counter);
+		var popup = $('popup_'+counter);
+		addr.setAttribute("id", "addr_"+(counter-1));
+		addr.setAttribute("name", "addr_"+(counter-1));
+		popup.setAttribute("name", "popup_"+(counter-1));
+		popup.setAttribute("id", "popup_"+(counter-1));
+		counter++;
+		currentRow = $('row_' + counter);
+	}
+	lastIndex--;
 }
 
-function fancyAddRow(text, type) {
+function fancyAddRow(text, type, focus) {
     var addr = $('addr_' + lastIndex);
     if (addr && addr.value == '') {
         var sub = $('subjectField');
@@ -63,14 +90,22 @@
     var addressList = $("addressList").tBodies[0];
     var lastChild = $("lastRow");
   
-    currentIndex++;
+    lastIndex++;
     var proto = lastChild.previous("tr");
     var row = proto.cloneNode(true);
-    row.writeAttribute("id", 'row_' + currentIndex);
+    row.writeAttribute("id", 'row_' + lastIndex);
     var rowNodes = row.childNodesWithTag("td");
     var select = $(rowNodes[0]).childNodesWithTag("select")[0];
-    select.name = 'popup_' + currentIndex;
-    select.value = (type? type : proto.down("select").value);
+    select.name = 'popup_' + lastIndex;
+    select.id = 'popup_' + lastIndex;
+    if (proto.down("select").value != 3) // Only one reply to is preferred
+    {
+	    select.value = (type? type : proto.down("select").value);
+    }
+    else
+    {
+	    select.value = (type? type : 0); // Force to
+    }
     var cell = $(rowNodes[1]);
     var input = cell.childNodesWithTag("input")[0];
     if (Prototype.Browser.IE) {
@@ -79,8 +114,8 @@
         cell.appendChild(input);
     }
     
-    input.name  = 'addr_' + currentIndex;
-    input.id = 'addr_' + currentIndex;
+    input.name  = 'addr_' + lastIndex;
+    input.id = 'addr_' + lastIndex;
     input.value = text;
     input.stopObserving();
     input.addInterface(SOGoAutoCompletionInterface);
@@ -89,7 +124,11 @@
     input.observe("blur", addressFieldLostFocus.bind(input));
     input.observe("autocompletion:changedlist", expandContactList);
     input.on("autocompletion:changed", addressFieldChanged.bind(input));
-    input.focus();
+    if (focus)
+    {
+	    input.focus();  // It's a bad idea as on adding from selecting new item from from field, this will trigger cleanup
+	    // But when the user adds manualy a new item it must be updated
+    }
 
     return input;
 }
@@ -122,7 +161,7 @@
                     var text = data[i][2];
                     if (data[i][1].length)
                       text = data[i][1] + " <" + data[i][2] + ">";
-                    fancyAddRow(text, $(input).up("tr").down("select").value);
+                    fancyAddRow(text, $(input).up("tr").down("select").value, true);
                 }
             }
         }
@@ -172,7 +211,7 @@
                             first = false;
                         }
                         else
-                            fancyAddRow(phrase.join(' '), $(this).up("tr").down("select").value);
+                            fancyAddRow(phrase.join(' '), $(this).up("tr").down("select").value, true);
                     
                         phrase = new Array();
                     }
@@ -189,7 +228,7 @@
                         first = false;
                     }
                     else
-                        fancyAddRow(word, $(this).up("tr").down("select").value);
+                        fancyAddRow(word, $(this).up("tr").down("select").value, true);
                 }
                 
                 phrase = new Array();
@@ -216,11 +255,12 @@
     addressList = $("addressList").tBodies[0];
   
     if (lastIndex == 0 && addressList.childNodes.length <= 2) return;
-    addr = $('addr_' + lastIndex);
+	    addr = $('addr_' + lastIndex);
     if (!addr) return;
     if (addr.value.strip() != '') return;
     senderRow = $("row_" + lastIndex);
     addressList.removeChild(senderRow);
+    lastIndex--;
 }
 
 function getIndexFromIdentifier(id) {
@@ -277,7 +317,7 @@
 }
 
 function initMailToSelection() {
-    currentIndex = lastIndex = $$("table#addressList tr").length - 2;
+    lastIndex = $$("table#addressList tr").length - 2;
 }
 
 document.observe("dom:loaded", initMailToSelection);
diff -ur sogo-2.0.3a/UI/WebServerResources/UIxPreferences.js sogo-2.0.3a-my/UI/WebServerResources/UIxPreferences.js
--- sogo-2.0.3a/UI/WebServerResources/UIxPreferences.js	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/UI/WebServerResources/UIxPreferences.js	2013-01-08 15:03:13.000000000 +0100
@@ -460,26 +460,29 @@
         }
     }
 
-    var inputs = $$("#accountInfo input");
-    for (var i = 0; i < inputs.length; i++) {
-        $(inputs[i]).observe("change", onMailAccountInfoChange);
-    }
-
-    inputs = $$("#identityInfo input");
-    for (var i = 0; i < inputs.length; i++) {
-        $(inputs[i]).observe("change", onMailIdentityInfoChange);
-    }
-    $("actSignature").observe("click", onMailIdentitySignatureClick);
-    displayMailAccount(mailAccounts[0], true);
-
-    inputs = $$("#returnReceiptsInfo input");
-    for (var i = 0; i < inputs.length; i++) {
-        $(inputs[i]).observe("change", onMailReceiptInfoChange);
-    }
-    inputs = $$("#returnReceiptsInfo select");
-    for (var i = 0; i < inputs.length; i++) {
-        $(inputs[i]).observe("change", onMailReceiptActionChange);
-    }
+	    var inputs = $$("#accountInfo input");
+	    for (var i = 0; i < inputs.length; i++) {
+		$(inputs[i]).observe("change", onMailAccountInfoChange);
+	    }
+
+	    inputs = $$("#identityInfo input");
+	    for (var i = 0; i < inputs.length; i++) {
+		$(inputs[i]).observe("change", onMailIdentityInfoChange);
+	    }
+	    if (!hasExtendedIdentities)
+	    {
+		    $("actSignature").observe("click", onMailIdentitySignatureClick);
+	    }
+	    displayMailAccount(mailAccounts[0], true);
+
+	    inputs = $$("#returnReceiptsInfo input");
+	    for (var i = 0; i < inputs.length; i++) {
+		$(inputs[i]).observe("change", onMailReceiptInfoChange);
+	    }
+	    inputs = $$("#returnReceiptsInfo select");
+	    for (var i = 0; i < inputs.length; i++) {
+		$(inputs[i]).observe("change", onMailReceiptActionChange);
+	    }
 }
 
 function onMailAccountInfoChange(event) {
@@ -687,11 +690,15 @@
     var identity = (mailAccount["identities"]
                     ? mailAccount["identities"][0]
                     : {} );
-    $("fullName").value = identity["fullName"] || "";
-    $("email").value = identity["email"] || "";
-    $("replyTo").value = identity["replyTo"] || "";
 
-    displayAccountSignature(mailAccount);
+    if (!hasExtendedIdentities)
+    {
+	    $("fullName").value = identity["fullName"] || "";
+	    $("email").value = identity["email"] || "";
+	    $("replyTo").value = identity["replyTo"] || "";
+
+	    displayAccountSignature(mailAccount);
+    }
 
     var receiptAction = "ignore";
     var receiptActionValues = [ "ignore", "allow" ];
diff -ur sogo-2.0.3a/SoObjects/SOGo/LDAPSource.h sogo-2.0.3a-my/SoObjects/SOGo/LDAPSource.h
--- sogo-2.0.3a/SoObjects/SOGo/LDAPSource.h	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/LDAPSource.h	2013-01-08 12:42:27.000000000 +0100
@@ -96,6 +96,10 @@
 
   /* ACL */
   NSArray *modifiers;
+
+  /* Extended identities */
+  NSDictionary * extIdOpts;
+
 }
 
 - (void) setBindDN: (NSString *) newBindDN
diff -ur sogo-2.0.3a/SoObjects/SOGo/LDAPSource.m sogo-2.0.3a-my/SoObjects/SOGo/LDAPSource.m
--- sogo-2.0.3a/SoObjects/SOGo/LDAPSource.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/LDAPSource.m	2013-01-08 13:43:02.000000000 +0100
@@ -160,6 +160,7 @@
   [searchAttributes release];
   [domain release];
   [_dnCache release];
+  [extIdOpts release];
   [kindField release];
   [multipleBookingsField release];
   [MSExchangeHostname release];
@@ -200,6 +201,7 @@
 	   bindFields: [udSource objectForKey: @"bindFields"]
 	    kindField: [udSource objectForKey: @"KindFieldName"]
             andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
+	
 
       dotValue = [udSource objectForKey: @"listRequiresDot"];
       if (dotValue)
@@ -218,6 +220,11 @@
       else
         dd = [SOGoSystemDefaults sharedSystemDefaults];
 
+	
+      extIdOpts = [dd extendedLDAPIdentitySettings];
+      if (extIdOpts)
+	      [extIdOpts retain]; 
+
       contactInfoAttribute
         = [udSource objectForKey: @"SOGoLDAPContactInfoAttribute"];
       if (!contactInfoAttribute)
@@ -507,6 +514,153 @@
   return userDN;
 }
 
+/** EI means Extended Identity */
+- (NSString *) _EIMapField: (NSString *) field 
+{
+
+	return [extIdOpts objectForKey: field];
+}
+
+- (NSString *) _EIFormat: (NSString *) field forLogin: (NSString *)login
+{
+	NSString * tmp = [extIdOpts objectForKey: field];
+	NSMutableString * s = [NSMutableString stringWithString: tmp];
+	NSString * _domain = domain;
+
+	if (!_domain)
+		_domain = @"";
+
+	s = [[s stringByReplacingOccurrencesOfString: @"%U" withString: login ]
+		stringByReplacingOccurrencesOfString: @"%D" withString: _domain ];
+	
+	return s;
+}
+
+- (NSArray *) lookupExtIdentitiesFor: (NSString *) login
+{
+NSEnumerator *entries;
+  EOQualifier *qualifier;
+  NSArray *attributes;
+  NGLdapConnection *ldapConnection;
+  NGLdapEntry * ent;
+  NSMutableArray * rv = [NSMutableArray arrayWithCapacity: 10];
+
+  // TODO: make it configurable
+  NSString * myBaseDN = [self _EIFormat: @"baseDN" forLogin: login];
+
+
+  ldapConnection = [self _ldapConnection];
+  qualifier = [EOQualifier qualifierWithQualifierFormat: [ self _EIFormat: @"filter" forLogin: login ]];
+  attributes = [NSArray arrayWithObjects: 
+  			[self _EIMapField: @"identityCC"],
+			[self _EIMapField: @"identityBCC"],
+			[self _EIMapField: @"identityReplyTo"],
+			[self _EIMapField: @"identityFromAddress"],
+			[self _EIMapField: @"identityFromName"],
+			[self _EIMapField: @"identitySignature"],
+			[self _EIMapField: @"identityConfirmed"],
+			[self _EIMapField: @"identityWeight"],
+			nil
+  			];
+
+  NSLog(@"my query is running");
+  entries = [ldapConnection deepSearchAtBaseDN: myBaseDN
+                                       qualifier: qualifier
+                                      attributes: attributes];
+  NSLog(@"my query is done rv = %@", entries);
+
+  while ((ent = [entries nextObject]))
+  {
+  	NSMutableDictionary * identity = [NSMutableDictionary dictionary];
+	NGLdapAttribute * a;
+
+	a = [ent attributeWithName: [self _EIMapField:@"identityConfirmed"] ];
+	if (a)
+	{
+		NSArray * val = [a allValues];
+		if (![val objectAtIndex: 0])
+		{
+			continue;
+		}
+	}
+
+	a = [ent attributeWithName: [self _EIMapField:@"identityWeight"] ];
+	if (a)
+	{
+		[identity setValue: [a stringValueAtIndex: 0] forKey: @"weight"];
+	}
+	else
+	{
+		[identity setValue: @"-999" forKey: @"weight"];
+	}
+
+	a = [ent attributeWithName: [self _EIMapField:@"identityFromAddress"]];
+	if (a)
+		[identity setValue: [a stringValueAtIndex: 0]
+				    forKey: @"email" ];
+	else
+	{
+		NSLog(@"Identity does not contain identityFromAddress, ignoring it (user=%@,domain=%@,entry=%@)", 
+			login, domain, ent);
+		continue;
+	}
+	
+	a = [ent attributeWithName: [self _EIMapField:@"identityFromName"] ];
+	if (a)
+		[identity setValue: [a stringValueAtIndex: 0 ] forKey: @"fullName"];
+
+	a = [ent attributeWithName: [self _EIMapField: @"identityReplyTo"] ];
+	if (a)
+		[identity setValue: [a stringValueAtIndex: 0 ] forKey: @"replyTo"];
+
+	a = [ent attributeWithName: [self _EIMapField:@"identitySignature"] ];
+	if (a)
+		[identity setValue: [a stringValueAtIndex: 0 ] forKey: @"signature"];
+
+	a = [ent attributeWithName: [self _EIMapField:@"identityBCC"] ];
+	if (a)
+	{
+		NSMutableArray * tmp = [NSMutableArray arrayWithCapacity: 50];
+		int i;
+		for (i = 0; i < [a count]; i++)
+		{
+			[tmp addObject: [a stringValueAtIndex: i]];
+		}
+
+		[identity setValue: tmp forKey: @"bcc"];
+	}
+	a = [ent attributeWithName: [self _EIMapField:@"identityCC"] ];
+	if (a)
+	{
+		NSMutableArray * tmp = [NSMutableArray arrayWithCapacity: 50];
+		int i;
+		for (i = 0; i < [a count]; i++)
+		{
+			[tmp addObject: [a stringValueAtIndex: i]];
+		}
+
+		[identity setValue: tmp forKey: @"cc"];
+	}
+
+	[rv addObject: identity];	
+  }
+
+  if ([rv count] == 0)
+  {
+  	return nil;
+  }
+
+
+  // Let's sort the identities based on weights
+  NSSortDescriptor * mySortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"weight" ascending:YES];
+  NSArray * mySortDescriptors = [ NSArray arrayWithObjects: mySortDescriptor, nil ];
+  NSArray * finalValue = [rv sortedArrayUsingDescriptors:mySortDescriptors];
+
+  NSLog(@"Identity array for %@@%@ is %@", login, domain, finalValue);
+
+  return finalValue;
+}
+
 //
 //
 //
@@ -819,6 +973,8 @@
         [ids addObject: value];
     }
 
+  [attributes release];
+  [qs release];
   return ids;
 }
 
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoDefaults.plist sogo-2.0.3a-my/SoObjects/SOGo/SOGoDefaults.plist
--- sogo-2.0.3a/SoObjects/SOGo/SOGoDefaults.plist	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoDefaults.plist	2013-01-08 13:22:42.000000000 +0100
@@ -72,4 +72,19 @@
     SOGoRemindWithASound = YES;
 
     SOGoSearchMinimumWordLength = 2;
+
+    SOGoMailExtendedIdentities = NO;
+    SOGoMailExtendedLDAPIdentitySettings  = {
+	baseDN = "uid=%U,ou=people,dc=caesar,dc=elte,dc=hu";
+	filter = "(objectClass=mailIdentity)";
+	identityBCC = "identityBCC";
+	identityCC = "identityCC";
+	identityConfirmed = "identityConfirmed";
+	identityFromAddress = "identityFromAddress";
+	identityFromName = "identityFromName";
+	identityReplyTo = "identityReplyTo";
+	identitySignature = "identitySignature";
+	identityWeight = "identityWeight";
+	};
+
 }
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoDomainDefaults.h sogo-2.0.3a-my/SoObjects/SOGo/SOGoDomainDefaults.h
--- sogo-2.0.3a/SoObjects/SOGo/SOGoDomainDefaults.h	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoDomainDefaults.h	2013-01-08 13:19:03.000000000 +0100
@@ -63,6 +63,7 @@
 - (BOOL) aclSendEMailNotifications;
 - (BOOL) appointmentSendEMailNotifications;
 - (BOOL) foldersSendEMailNotifications;
+- (BOOL) extendedIdentities;
 - (NSArray *) calendarDefaultRoles;
 - (NSArray *) contactsDefaultRoles;
 - (NSArray *) mailPollingIntervals;
@@ -81,6 +82,7 @@
 - (int) searchMinimumWordLength;
 - (BOOL) notifyOnPersonalModifications;
 - (BOOL) notifyOnExternalModifications;
+- (NSDictionary *) extendedLDAPIdentitySettings;
 
 @end
 
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoDomainDefaults.m sogo-2.0.3a-my/SoObjects/SOGo/SOGoDomainDefaults.m
--- sogo-2.0.3a/SoObjects/SOGo/SOGoDomainDefaults.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoDomainDefaults.m	2013-01-08 13:24:21.000000000 +0100
@@ -146,6 +146,15 @@
   return [self boolForKey: @"SOGoIMAPAclConformsToIMAPExt"];
 }
 
+- (BOOL) extendedIdentities
+{
+  return [self boolForKey: @"SOGoMailExtendedIdentities"];
+}
+
+- (NSDictionary *) extendedLDAPIdentitySettings
+{
+  return [self dictionaryForKey: @"SOGoMailExtendedLDAPIdentitySettings"]; 
+}
 - (BOOL) aclSendEMailNotifications
 {
   return [self boolForKey: @"SOGoACLsSendEMailNotifications"];
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoSource.h sogo-2.0.3a-my/SoObjects/SOGo/SOGoSource.h
--- sogo-2.0.3a/SoObjects/SOGo/SOGoSource.h	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoSource.h	2013-01-08 13:32:14.000000000 +0100
@@ -59,6 +59,7 @@
 - (NSDictionary *) lookupContactEntry: (NSString *) theID;
 - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID
                                            inDomain: (NSString *) domain;
+- (NSArray *) lookupExtIdentitiesFor: (NSString *) login;
 
 - (NSArray *) allEntryIDs;
 - (NSArray *) fetchContactsMatching: (NSString *) filter
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoSystemDefaults.h sogo-2.0.3a-my/SoObjects/SOGo/SOGoSystemDefaults.h
--- sogo-2.0.3a/SoObjects/SOGo/SOGoSystemDefaults.h	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoSystemDefaults.h	2013-01-08 13:19:00.000000000 +0100
@@ -47,6 +47,8 @@
 
 - (BOOL) isWebAccessEnabled;
 - (BOOL) isCalendarDAVAccessEnabled;
+- (BOOL) extendedIdentities;
+
 - (BOOL) isAddressBookDAVAccessEnabled;
 
 - (BOOL) enableEMailAlarms;
@@ -84,6 +86,7 @@
 - (BOOL) SAML2LogoutEnabled;
 
 - (BOOL) enablePublicAccess;
+- (NSDictionary *) extendedLDAPIdentitySettings;
 
 @end
 
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoSystemDefaults.m sogo-2.0.3a-my/SoObjects/SOGo/SOGoSystemDefaults.m
--- sogo-2.0.3a/SoObjects/SOGo/SOGoSystemDefaults.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoSystemDefaults.m	2013-01-08 13:24:32.000000000 +0100
@@ -210,6 +210,12 @@
           | [super migrate]);
 }
 
+- (BOOL) extendedIdentities
+{
+  return [self boolForKey: @"SOGoMailExtendedIdentities"];
+}
+
+
 - (NSArray *) domainIds
 {
   return [[self dictionaryForKey: @"domains"] allKeys];
@@ -461,4 +467,8 @@
   return [self boolForKey: @"SOGoEnablePublicAccess"];
 }
 
+- (NSDictionary *) extendedLDAPIdentitySettings
+{
+  return [self dictionaryForKey: @"SOGoMailExtendedLDAPIdentitySettings"]; 
+}
 @end
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoUser.h sogo-2.0.3a-my/SoObjects/SOGo/SOGoUser.h
--- sogo-2.0.3a/SoObjects/SOGo/SOGoUser.h	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoUser.h	2013-01-08 14:08:35.000000000 +0100
@@ -115,6 +115,7 @@
 - (NSArray *) allIdentities;
 - (NSDictionary *) primaryIdentity;
 - (NSMutableDictionary *) defaultIdentity;
+- (BOOL) hasExtendedIdentities;
 
 - (BOOL) isSuperUser;
 - (BOOL) canAuthenticate;
diff -ur sogo-2.0.3a/SoObjects/SOGo/SOGoUser.m sogo-2.0.3a-my/SoObjects/SOGo/SOGoUser.m
--- sogo-2.0.3a/SoObjects/SOGo/SOGoUser.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SOGoUser.m	2013-01-08 14:44:19.000000000 +0100
@@ -701,25 +701,35 @@
       identity = [NSMutableDictionary new];
       fullName = [self cn];
       if (![fullName length])
-        fullName = login;
+	fullName = login;
       [identity setObject: fullName forKey: @"fullName"];
       [identity setObject: [mails objectAtIndex: count] forKey: @"email"];
 
       if ([replyTo length] > 0)
-        [identity setObject: replyTo forKey: @"replyTo"];
+	[identity setObject: replyTo forKey: @"replyTo"];
 
       signature = [_defaults mailSignature];
       if (signature)
-        [identity setObject: signature forKey: @"signature"];
+	[identity setObject: signature forKey: @"signature"];
       [identities addObject: identity];
       [identity release];
     }
   [[identities objectAtIndex: 0] setObject: [NSNumber numberWithBool: YES]
-                                    forKey: @"isDefault"];
+				    forKey: @"isDefault"];
   
   [mailAccount setObject: identities forKey: @"identities"];
   [identities release];
 
+    /** Extended identity support */
+    if ([[self domainDefaults ] extendedIdentities])
+    {
+    	NSArray * a= [[self authenticationSource] lookupExtIdentitiesFor: [self loginInDomain]];
+	if (a != nil)
+	{
+		[mailAccount setObject: a forKey: @"identities"];
+	}
+    }
+
   /* receipts */
   if ([_defaults allowUserReceipt])
     {
@@ -757,6 +767,20 @@
   [mailAccount release];
 }
 
+- (BOOL) hasExtendedIdentities
+{
+    /** Extended identity support */
+    if ([[self domainDefaults ] extendedIdentities])
+    {
+    	NSArray * a= [[self authenticationSource] lookupExtIdentitiesFor: [self loginInDomain]];
+	if (a != nil)
+	{
+		return YES;
+	}
+    }
+    return NO;
+
+}
 - (NSArray *) mailAccounts
 {
   NSArray *auxAccounts;
@@ -929,4 +953,5 @@
   return [accessValue boolValue];
 }
 
+
 @end /* SOGoUser */
diff -ur sogo-2.0.3a/SoObjects/SOGo/SQLSource.m sogo-2.0.3a-my/SoObjects/SOGo/SQLSource.m
--- sogo-2.0.3a/SoObjects/SOGo/SQLSource.m	2012-12-07 16:17:02.000000000 +0100
+++ sogo-2.0.3a-my/SoObjects/SOGo/SQLSource.m	2013-01-08 13:31:52.000000000 +0100
@@ -878,4 +878,12 @@
                                userInfo: nil];
 }
 
+
+// TODO!
+- (NSArray *) lookupExtIdentitiesFor: (NSString *) login 
+{
+	NSLog(@"Should not call lookupExtIdentitiesFor on SQL Source as its not implemented!");
+	return nil;
+}
+
 @end
ludovic

ludovic

2013-01-09 16:12

administrator   ~0005098

While interesting, I think the whole thing is very complex, especially regarding the schema modifications.

Why wouldn't we store this in the sogo_user_profile table? The identity editor should be just like the one found in Thunderbird.

turip

turip

2013-01-09 17:01

reporter   ~0005104

You've got right pragmatically, but if you view sogo as a part of a greater system I must oppose your idea.

SOGo is a kick-ass solution for groupware related problems, but it cannot solve all the issues raised when trying to satisfy all the requirements of even 30k users of our universities as SOGo is not a web publication platform or a collaboration framework. We must be able to integrate such features into our system and using LDAP as a settings storage has serious advantages in such an environment.

SOGo also cannot administer the underlying mail server or mail gateway. This is the role of the corporate Identity Management System and the Authentication and Authorization Infrastructure(which both we employ to coordinate other components such as AFS, Web, Database access, WiFi etc.).

A Identity Managment System can - of course - modify any data in any system, but if you use too much 3rd party products the whole thing becomes a mess. LDAP is good for communication between systems as it's schema describes the actual data without details on the actual representation and it is universal in the sense that it can be connected to almost anything.

Now reflecting on your observation, i'd rather recommend that I change the SOGoMailExtenededIdentity BOOL value to a string with the following valueset:

  • 'none' (until the identity support is complete this must be the default value): using the legacy behaviour
  • 'ldap' no identity editing features on preferences, identities are from the ldap directory (good for institutes using IMS and AAI applications)
  • 'profile' (default after the editing is complete) identity data is stored in the preferences table, full-fledged editor is available to the masses
  • 'sql' truly: don't have an idea :)

The idea behind this is the following:

'profile' value pros and cons

Storing the data in the sogo_user_profile table is good for small-scale deployments as it's easily configurable, requires no expertise on ldap and also the user is given full control on their identities.

It's bad because:

  • To modify the identity setting from an external source you have to modify a 3rd party data structure as opposed to the cleanness of the LDAP.

'ldap' value pros and cons

Storing the data in LDAP is good for institutes using IMS and AAI applications.

Pros:
LDAP schema is well defined, so if you want to change your webmail application, or provide multiple applications to the users (e.g.: mobile compatilbe webmail AND sogo) or just want to replace your current solution much less hustle is needed to do so.

The attached LDAP schema is from an IANA registered OID of which we are the owners so it is universal. Also please note that LDAP schema change is not black magic, it's just like if you are adding a new table to SQL.

Also a few tricks could be done using ldap. Consider these settings:

bindDN = "dc=aliases,ou=people,...."
filter = "(&(objectClass=mailIdentity)(member=%U))"

Now if you create entries like this:

dn: identityFromAddress=sdsadystem@caesar.elte.hu,ou=aliases,...
objectClass: top
objectClass: mailIdentity
objectClass: someGroupType
member: turip
member: joe
identityBCC: Caesar rendszergazda <sydsastem@caesar.elte.hu>
identityFromName: Caesar rendszergazda
identityConfirmed: TRUE
identitySignature: Caesar rendszergazda stb
identityFromAddress: sydsastem@caesar.elte.hu
identityReplyTo: norepdsly@caesar.elte.hu
identityWeight: 10

Then all users who are entitled to the given alias will automagically see their new identity. Furthermore these objects can be processed by the mail server to decide on where to deliver the actual mail.

Also it must be noted that on faulty links (such as an interconnect between organizational sites) replication using SQL is much harder than implementing replication based LDAP (using the last writer wins stregy).

I can provide the required modifications to be able to select identity backends, and will investigate the posibility of storage of identities in sogo_user_profile if you are interested in this patch. What I'm not into is the implementation of the UI for editing the identities (as we are providing a seperate UI @ our university) and also the SQLSource patch seems uninteresting for me.

turip

turip

2013-01-09 18:23

reporter   ~0005110

As it seems that I'll have more work with this I've forked sogo:

https://github.com/turip/sogo

turip

turip

2014-02-26 11:09

reporter   ~0006570

Update on the status: we have been using this patch for a while, however we don't/won't have enough resources to complete this patch to be as universal as requested.

So I was thinking of the following:

  • What about splitting the whole stuff into ldap specific part and frontend specific part?
  • Frontend specific patches can go into the upstream, which would include proper handling of identity array when composing a new message.
  • The LDAP part will remain the same, won't go upstream we will have our patch locally managed.
  • On the roadmap there's an entry: Add scripting capabilities using PyObjc.
    -- What about providing a hook using pyobjc for alternative identity generation?

Of course the last idea depends on the pyobjc integration on which I can hardly find any information.

stf

stf

2016-06-09 14:56

reporter   ~0010338

what is the status here? i also would be very interested in multiple identities... even Horde and Roundcube do support this..

Issue History

Date Modified Username Field Change
2013-01-09 08:54 turip New Issue
2013-01-09 08:54 turip File Added: sogo-2.0.3a-multi-identity.patch
2013-01-09 14:04 ludovic Target Version => 2.0.4
2013-01-09 16:12 ludovic Note Added: 0005098
2013-01-09 17:01 turip Note Added: 0005104
2013-01-09 18:23 turip Note Added: 0005110
2013-01-14 19:45 ludovic Target Version 2.0.4 => soon
2014-02-26 11:09 turip Note Added: 0006570
2016-06-09 14:56 stf Note Added: 0010338