]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1192 d1b88da0-ebda-0310...
authorwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Mon, 22 Oct 2007 22:02:17 +0000 (22:02 +0000)
committerwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Mon, 22 Oct 2007 22:02:17 +0000 (22:02 +0000)
30 files changed:
ChangeLog
Main/sogod.m
NEWS
SOPE/sope-patchset-r1545.diff [new file with mode: 0644]
SoObjects/Mailer/SOGoMailAccount.m
SoObjects/Mailer/SOGoMailFolder.h
SoObjects/Mailer/SOGoMailFolder.m
SoObjects/SOGo/SOGoContentObject.m
SoObjects/SOGo/SOGoFolder.m
UI/MailerUI/English.lproj/Localizable.strings
UI/MailerUI/French.lproj/Localizable.strings
UI/MailerUI/German.lproj/Localizable.strings
UI/MailerUI/UIxMailActions.m
UI/MailerUI/UIxMailFolderActions.m
UI/MailerUI/UIxMailListView.m
UI/MailerUI/product.plist
UI/MainUI/product.plist
UI/Templates/ContactsUI/UIxContactsFilterPanel.wox
UI/Templates/MailerUI/UIxMailFilterPanel.wox
UI/Templates/MailerUI/UIxMailListView.wox
UI/Templates/MailerUI/UIxMailMainFrame.wox
UI/Templates/SchedulerUI/UIxCalFilterPanel.wox
UI/Templates/SchedulerUI/UIxComponentEditor.wox
UI/WebServerResources/MailerUI.css
UI/WebServerResources/MailerUI.js
UI/WebServerResources/UIxAppointmentEditor.css
UI/WebServerResources/UIxMailEditor.js
UI/WebServerResources/UIxTaskEditor.css
UI/WebServerResources/generic.css
UI/WebServerResources/generic.js

index 33493d6da1d6990008ab00535d0c35a84cd0b87a..63b2fea8e6b79994c816fb0a3291a2c46bd2291d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2007-10-22  Wolfgang Sourdeau  <wsourdeau@inverse.ca>
+
+       * UI/MailerUI/UIxMailActions.m ([UIxMailActions
+       -removeAllLabelsAction]): new method that removes all label flags
+       from the associated message.
+       ([UIxMailActions -addLabel1Action]
+       [UIxMailActions -addLabel2Action]
+       [UIxMailActions -addLabel3Action
+       [UIxMailActions -addLabel4Action]
+       [UIxMailActions -addLabel5Action]): new methods that adds label
+       flags to the associated message.
+       ([UIxMailActions -removeLabel1Action]
+       [UIxMailActions -removeLabel2Action]
+       [UIxMailActions -removeLabel3Action
+       [UIxMailActions -removeLabel4Action]
+       [UIxMailActions -removeLabel5Action]): new methods that removes
+       label flags from the associated message.
+
+       * UI/MailerUI/UIxMailListView.m ([UIxMailListView -msgLabels]):
+       new accessor that returns the labels associated with the message.
+
+       * SoObjects/Mailer/SOGoMailFolder.m ([SOGoMailFolder
+       -allFolderPaths]): new method that returns all the paths of all
+       the subfolders of the folder object.
+       ([SOGoMailFolder -allFolderURLs]): new method replacing
+       subfoldersURL.
+
+       * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject
+       -aclsForUser:uid]): object inherits the 'SOGoRole_ObjectEditor'
+       role from its parent folder.
+
 2007-10-19  Francis Lachapelle  <flachapelle@inverse.ca>
 
        * SoObjects/SOGo/SOGoUser.m 
index fc8583034292d2e673f7b40a77fe617187d02568..8c13c03864b96a86cedc832379fdb344242cf3e9 100644 (file)
@@ -43,7 +43,8 @@ main (int argc, char **argv, char **env)
   if (getuid() > 0)
     {
 #if LIB_FOUNDATION_LIBRARY
-      [NSProcessInfo initializeWithArguments: argv count: argc environment: env];
+      [NSProcessInfo initializeWithArguments: argv
+                    count: argc environment: env];
 #endif
       ud = [NSUserDefaults standardUserDefaults];
       rc = 0;
diff --git a/NEWS b/NEWS
index 95e1bff6376861934d7ce8feafa077a18f053b3d..e563d7fb5ffadc69c8383e72a732ea2babb369ac 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,9 +2,7 @@
 --------------
 - the user can now configure his folders as drafts, trash or sent folder;
 - added the ability the move and copy message across mail folders;
-
-0.9.0-200709XX
---------------
+- added the ability to label messages;
 - implemented cookie-based identification in the web interface;
 - fixed a bug where a false positive happening whenever a wrong user login was
   given during an indirect bind;
diff --git a/SOPE/sope-patchset-r1545.diff b/SOPE/sope-patchset-r1545.diff
new file mode 100644 (file)
index 0000000..5a61450
--- /dev/null
@@ -0,0 +1,510 @@
+Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.h
+===================================================================
+--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.h (révision 1545)
++++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.h (copie de travail)
+@@ -28,6 +28,7 @@
+ #define ___PostgreSQL72_Channel_H___
+ #include <GDLAccess/EOAdaptorChannel.h>
++#include <GDLContentStore/EOAdaptorChannel+GCS.h>
+ #include <libpq-fe.h>
+ @class NSArray, NSString, NSMutableDictionary;
+@@ -40,7 +41,7 @@
+   int        modification;
+ } PostgreSQL72FieldInfo;
+-@interface PostgreSQL72Channel : EOAdaptorChannel
++@interface PostgreSQL72Channel : EOAdaptorChannel <GCSEOAdaptorChannel>
+ {
+   // connection is valid after an openChannel call
+   PGConnection *connection;
+Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m
+===================================================================
+--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (révision 1545)
++++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (copie de travail)
+@@ -713,6 +713,39 @@
+   return ms;
+ }
++/* GCSEOAdaptorChannel protocol */
++static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n"    \
++                                  @"  c_name VARCHAR (256) NOT NULL,\n"
++                                  @"  c_content VARCHAR (100000) NOT NULL,\n"
++                                  @"  c_creationdate INT4 NOT NULL,\n"
++                                  @"  c_lastmodified INT4 NOT NULL,\n"
++                                  @"  c_version INT4 NOT NULL,\n"
++                                  @"  c_deleted INT4 NULL\n"
++                                  @")");
++static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \
++                                     @"  c_uid VARCHAR (256) NOT NULL,\n"
++                                     @"  c_object VARCHAR (256) NOT NULL,\n"
++                                     @"  c_role VARCHAR (80) NOT NULL\n"
++                                     @")");
++
++- (NSException *) createGCSFolderTableWithName: (NSString *) tableName
++{
++  NSString *sql;
++
++  sql = [NSString stringWithFormat: sqlFolderFormat, tableName];
++
++  return [self evaluateExpressionX: sql];
++}
++
++- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName
++{
++  NSString *sql;
++
++  sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName];
++
++  return [self evaluateExpressionX: sql];
++}
++
+ @end /* PostgreSQL72Channel */
+ @implementation PostgreSQL72Channel(PrimaryKeyGeneration)
+Index: sope-gdl1/Oracle8/ChangeLog
+===================================================================
+--- sope-gdl1/Oracle8/ChangeLog        (révision 1545)
++++ sope-gdl1/Oracle8/ChangeLog        (copie de travail)
+@@ -1,3 +1,10 @@
++2007-10-19      Ludovic Marcotte <ludovic@inverse.ca>
++
++      * We call OCITerminate() in OracleAdaptorChannel:
++        -closeChannel:       
++      * Some formatting cleanups.
++
++
+ 2007-10-05    Ludovic Marcotte <ludovic@inverse.ca>
+       * Fixed otest wrt bundle name.
+Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m
+===================================================================
+--- sope-gdl1/Oracle8/OracleAdaptorChannel.m   (révision 1545)
++++ sope-gdl1/Oracle8/OracleAdaptorChannel.m   (copie de travail)
+@@ -112,7 +112,7 @@
+   // Oracle's doc says: "If you call OCIStmtFetch2() with the nrows parameter set to 0, this cancels the cursor."
+   if (OCIStmtFetch2(_current_stm, _oci_err, (ub4)0, (ub4)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT))
+     {
+-      NSLog( @"Fetch cancellation failed");
++      NSLog(@"Fetch cancellation failed");
+     }
+   
+   [self _cleanup];
+@@ -131,8 +131,13 @@
+       // We logoff from the database.
+       if (OCILogoff(_oci_ctx, _oci_err))
+       {
+-        NSLog( @"FAILED: OCILogoff()");
++        NSLog(@"FAILED: OCILogoff()");
+       }
++
++      if (OCITerminate(OCI_DEFAULT))
++      {
++        NSLog(@"FAILED: OCITerminate()");
++      }
+     }
+ }
+@@ -369,19 +374,19 @@
+                     (dvoid * (*)(dvoid *, dvoid *, size_t))0,
+                     (void (*)(dvoid *, dvoid *)) 0 ))
+     {
+-      NSLog( @"FAILED: OCIInitialize()");
++      NSLog(@"FAILED: OCIInitialize()");
+       return NO;
+     }
+   
+   if (OCIEnvInit((OCIEnv **)&_oci_env, (ub4)OCI_DEFAULT, (size_t)0, (dvoid **)0))
+     {
+-      NSLog( @"FAILED: OCIEnvInit()");
++      NSLog(@"FAILED: OCIEnvInit()");
+       return NO;
+     }
+   
+   if (OCIHandleAlloc((dvoid *)_oci_env, (dvoid *)&_oci_err, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0))
+     {
+-      NSLog( @"FAILED: OCIHandleAlloc() on errhp");
++      NSLog(@"FAILED: OCIHandleAlloc() on errhp");
+       return NO;
+     }
+   
+@@ -398,7 +403,7 @@
+   if (OCILogon(_oci_env, _oci_err, &_oci_ctx, (const OraText*)username, strlen(username),
+              (const OraText*)password, strlen(password), (const OraText*)database, strlen(database)))
+     {
+-      NSLog( @"FAILED: OCILogon(). username = %s  password = %s"
++      NSLog(@"FAILED: OCILogon(). username = %s  password = %s"
+           @"  database = %s", username, password, database);
+       return NO;
+     }
+Index: sope-mime/NGImap4/NGImap4Connection.m
+===================================================================
+--- sope-mime/NGImap4/NGImap4Connection.m      (révision 1545)
++++ sope-mime/NGImap4/NGImap4Connection.m      (copie de travail)
+@@ -381,7 +381,7 @@
+   
+   if (debugCache) [self logWithFormat:@"  no folders cached yet .."];
+   
+-  result = [[self client] list:(onlyFetchInbox ? @"INBOX" : @"*")
++  result = [[self client] list:(onlyFetchInbox ? @"INBOX" : @"")
+                         pattern:@"*"];
+   if (![[result valueForKey:@"result"] boolValue]) {
+     [self errorWithFormat:@"Could not list mailbox hierarchy!"];
+Index: sope-mime/NGImap4/NGImap4ResponseParser.m
+===================================================================
+--- sope-mime/NGImap4/NGImap4ResponseParser.m  (révision 1545)
++++ sope-mime/NGImap4/NGImap4ResponseParser.m  (copie de travail)
+@@ -84,6 +84,8 @@
+ static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self,
+                                        BOOL isBodyStructure);
++static NSArray *_parseLanguages();
++
+ static NSString *_parseBodyString(NGImap4ResponseParser *self,
+                                   BOOL _convertString);
+ static NSString *_parseBodyDecodeString(NGImap4ResponseParser *self,
+@@ -1627,6 +1629,29 @@
+   return _parseBodyDecodeString(self, _convertString, NO /* no decode */);
+ }
++static NSArray *_parseLanguages(NGImap4ResponseParser *self) {
++  NSMutableArray *languages;
++  NSString *language;
++
++  languages = [NSMutableArray array];
++  if (_la(self, 0) == '(') {
++    while (_la(self, 0) != ')') {
++      _consume(self,1);
++      language = _parseBodyString(self, YES);
++      if ([language length])
++      [languages addObject: language];
++    }
++    _consume(self,1);
++  }
++  else {
++    language = _parseBodyString(self, YES);
++    if ([language length])
++      [languages addObject: language];
++  }
++
++  return languages;
++}
++
+ static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self)
+ {
+   NSMutableDictionary *list;
+@@ -1734,10 +1759,11 @@
+                     *encoding, *bodysize;
+   NSDictionary        *parameterList;
+   NSMutableDictionary *dict;
++  NSArray           *languages;
+   type = [_parseBodyString(self, YES) lowercaseString];
+   _consumeIfMatch(self, ' ');
+-  subtype = _parseBodyString(self, YES);
++  subtype = [_parseBodyString(self, YES) lowercaseString];
+   _consumeIfMatch(self, ' ');
+   parameterList = _parseBodyParameterList(self);
+   _consumeIfMatch(self, ' ');
+@@ -1762,7 +1788,8 @@
+     _consumeIfMatch(self, ' ');
+     [dict setObject:_parseBodyString(self, YES) forKey:@"lines"];
+   }
+-  else if ([type isEqualToString:@"message"]) {
++  else if ([type isEqualToString:@"message"]
++         && [subtype isEqualToString:@"rfc822"]) {
+     if (_la(self, 0) != ')') {
+       _consumeIfMatch(self, ' ');
+       _consumeIfMatch(self, '(');
+@@ -1805,14 +1832,9 @@
+             forKey: @"disposition"];
+       if (_la(self, 0) != ')') {
+         _consume(self,1);
+-        if (_la(self, 0) == '(') {
+-          [dict setObject: _parseBodyParameterList(self)
+-                forKey: @"language"];
+-        }
+-        else {
+-          [dict setObject: _parseBodyString(self, YES)
+-                forKey: @"language"];
+-        }
++        languages = _parseLanguages(self);
++        if ([languages count])
++          [dict setObject: languages forKey: @"languages"];
+         if (_la(self, 0) != ')') {
+           _consume(self,1);
+           [dict setObject: _parseBodyString(self, YES)
+@@ -1829,6 +1851,7 @@
+ static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self,
+                                        BOOL isBodyStructure) {
+   NSMutableArray *parts;
++  NSArray      *languages;
+   NSString       *kind;
+   NSMutableDictionary *dict;
+@@ -1854,14 +1877,9 @@
+             forKey: @"disposition"];
+       if (_la(self, 0) != ')') {
+         _consume(self,1);
+-        if (_la(self, 0) == '(') {
+-          [dict setObject: _parseBodyParameterList(self)
+-                forKey: @"language"];
+-        }
+-        else {
+-          [dict setObject: _parseBodyString(self, YES)
+-                forKey: @"language"];
+-        }
++        languages = _parseLanguages(self);
++        if ([languages count])
++          [dict setObject: languages forKey: @"languages"];
+         if (_la(self, 0) != ')') {
+           _consume(self,1);
+           [dict setObject: _parseBodyString(self, YES)
+Index: sope-mime/NGMime/NGMimeBodyPart.m
+===================================================================
+--- sope-mime/NGMime/NGMimeBodyPart.m  (révision 1545)
++++ sope-mime/NGMime/NGMimeBodyPart.m  (copie de travail)
+@@ -31,18 +31,6 @@
+   return 2;
+ }
+-static NGMimeType *defaultType = nil;
+-
+-+ (void)initialize {
+-  static BOOL isInitialized = NO;
+-  if (!isInitialized) {
+-    isInitialized = YES;
+-    
+-    defaultType =
+-      [[NGMimeType mimeType:@"text/plain; charset=us-ascii"] retain];
+-  }
+-}
+-  
+ + (id)bodyPartWithHeader:(NGHashMap *)_header {
+   return [[[self alloc] initWithHeader:_header] autorelease];
+ }
+@@ -156,13 +144,12 @@
+   if (!Fields)
+     Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames];
+   
+-  
+   type = [self->header objectForKey:Fields->contentType];
+   
+   if (![type isKindOfClass:[NGMimeType class]])
+     type = [NGMimeType mimeType:[type stringValue]];
+   
+-  return (type != nil ? type : (id)defaultType);
++  return type;
+ }
+ - (NSString *)contentId {
+Index: sope-mime/NGMime/NGMimeBodyParser.m
+===================================================================
+--- sope-mime/NGMime/NGMimeBodyParser.m        (révision 1545)
++++ sope-mime/NGMime/NGMimeBodyParser.m        (copie de travail)
+@@ -67,7 +67,10 @@
+   if (_data == nil) return nil;
+   
+   ctype = [_part contentType];
+-  
++  if (!ctype
++      && [_d respondsToSelector: @selector(parser:contentTypeOfPart:)])
++    ctype = [_d parser: self contentTypeOfPart: _part];
++
+   if (![ctype isKindOfClass:[NGMimeType class]])
+     ctype = [NGMimeType mimeType:[ctype stringValue]];
+   
+Index: sope-mime/NGMime/NGMimePartParser.h
+===================================================================
+--- sope-mime/NGMime/NGMimePartParser.h        (révision 1545)
++++ sope-mime/NGMime/NGMimePartParser.h        (copie de travail)
+@@ -117,6 +117,7 @@
+     BOOL parserParseRawBodyDataOfPart:1;
+     BOOL parserBodyParserForPart:1;
+     BOOL parserDecodeBodyOfPart:1;
++    BOOL parserContentTypeOfPart:1;
+   } delegateRespondsTo;
+   
+@@ -275,6 +276,9 @@
+ - (id<NGMimeBodyParser>)parser:(NGMimePartParser *)_parser
+   bodyParserForPart:(id<NGMimePart>)_part;
++- (NGMimeType *)parser:(id)_parser
++  contentTypeOfPart:(id<NGMimePart>)_part;
++
+ @end /* NSObject(NGMimePartParserDelegate) */
+ @interface NSObject(NGMimePartParser)
+Index: sope-mime/NGMime/NGMimePartParser.m
+===================================================================
+--- sope-mime/NGMime/NGMimePartParser.m        (révision 1545)
++++ sope-mime/NGMime/NGMimePartParser.m        (copie de travail)
+@@ -1091,7 +1091,10 @@
+   id<NGMimeBodyParser> bodyParser   = nil;
+   
+   ctype = [_p contentType];
+-  
++  if (!ctype
++      && self->delegateRespondsTo.parserContentTypeOfPart)
++    ctype = [self->delegate parser: self contentTypeOfPart: _p];
++
+   contentType = ([ctype isKindOfClass:[NGMimeType class]])
+     ? ctype
+     : [NGMimeType mimeType:[ctype stringValue]];
+Index: sope-appserver/NGObjWeb/GNUmakefile.postamble
+===================================================================
+--- sope-appserver/NGObjWeb/GNUmakefile.postamble      (révision 1545)
++++ sope-appserver/NGObjWeb/GNUmakefile.postamble      (copie de travail)
+@@ -23,14 +23,20 @@
+ # install makefiles
+-after-install ::
++after-install :: $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make
++
++ifneq ($(GNUSTEP_MAKE_VERSION),1.3.0)
++after-install :: $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/woapp.make $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/wobundle.make
++endif
++
++$(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make: ngobjweb.make
+       $(MKDIRS) $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/
+       $(INSTALL_DATA) ngobjweb.make $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make
+-ifneq ($(GNUSTEP_MAKE_VERSION),1.3.0)
+-after-install ::
++$(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/woapp.make: woapp-gs.make
+       $(INSTALL_DATA) woapp-gs.make    \
+               $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/woapp.make
++
++$(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/wobundle.make: wobundle-gs.make
+       $(INSTALL_DATA) wobundle-gs.make \
+               $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/wobundle.make
+-endif
+Index: sope-appserver/NGObjWeb/WOContext.m
+===================================================================
+--- sope-appserver/NGObjWeb/WOContext.m        (révision 1545)
++++ sope-appserver/NGObjWeb/WOContext.m        (copie de travail)
+@@ -64,11 +64,13 @@
+ static BOOL     testNSURLs           = NO;
+ static BOOL     newCURLStyle         = NO;
+ static NSString *WOApplicationSuffix = nil;
++static NSURL    *redirectURL         = nil;
+ + (void)initialize {
+   static BOOL    didInit = NO;
+   NSUserDefaults *ud;
+   NSString       *cn;
++  NSString       *url;
+   if (didInit) return;
+@@ -91,6 +93,9 @@
+   debugCursor         = [ud boolForKey:@"WODebugCursor"] ? 1 : 0;
+   debugComponentAwake = [ud boolForKey:@"WODebugComponentAwake"];
+   WOApplicationSuffix = [[ud stringForKey:@"WOApplicationSuffix"] copy];
++  url                 = [ud stringForKey:@"WOApplicationRedirectURL"];
++  if (url != nil)
++    redirectURL       = [NSURL URLWithString: url];
+ }
+ + (id)contextWithRequest:(WORequest *)_r {
+@@ -503,6 +508,11 @@
+     return nil;
+   }
+   
++  if (redirectURL) {
++    // Use URL from user defaults (WOApplicationRedirectURL)
++    return redirectURL;
++  }
++  
+   if ((serverURL = [rq headerForKey:@"x-webobjects-server-url"]) == nil) {
+     if ((host = [rq headerForKey:@"host"]))
+       serverURL = [@"http://" stringByAppendingString:host];
+Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m
+===================================================================
+--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m  (révision 1545)
++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m  (copie de travail)
+@@ -216,6 +216,12 @@
+       assocCount++;
+     }
+   }
++  if (count > 0) {
++    if ((self->isAbsolute = OWGetProperty(_config, @"absolute"))) {
++      count--;
++      assocCount++;
++    }
++  }
+   
+   self->rest = _config;
+   
+Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m
+===================================================================
+--- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m      (révision 1545)
++++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m      (copie de travail)
+@@ -40,6 +40,7 @@
+   WOAssociation *string;
+   WOAssociation *target;
+   WOAssociation *disabled;
++  WOAssociation *isAbsolute;
+   WOElement     *template;
+   
+   /* new in WO4: */
+@@ -359,6 +360,7 @@
+ {
+   if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) {
+     self->href = _info->href;
++    self->isAbsolute = _info->isAbsolute;
+   }
+   return self;
+ }
+@@ -374,6 +376,9 @@
+   // TODO: we need a binding to disable rewriting!
+   NSRange  r;
+   
++  if ([[self->isAbsolute valueInContext:_ctx] boolValue] == YES)
++    return NO;
++
+   r = [_s rangeOfString:@":"];
+   if (r.length == 0) 
+     return YES;
+Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h
+===================================================================
+--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h  (révision 1545)
++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h  (copie de travail)
+@@ -41,7 +41,8 @@
+   WOAssociation *pageName;
+   WOAssociation *actionClass;
+   WOAssociation *directActionName;
+-  
++  WOAssociation *isAbsolute;
++
+   BOOL          sidInUrl;
+   /* 'ivar' associations */
+Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
+===================================================================
+--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m  (révision 1545)
++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m  (copie de travail)
+@@ -31,6 +31,7 @@
+ #include <NGObjWeb/WOCookie.h>
+ #include <NGExtensions/NSData+gzip.h>
+ #include <NGHttp/NGHttp.h>
++#include <NGMime/NGMimeType.h>
+ #include "common.h"
+ #include <string.h>
+@@ -1016,6 +1017,12 @@
+ - (void)parser:(NGMimePartParser *)_parser didParseHeader:(NGHashMap *)_header {
+ }
++- (NGMimeType *)parser:(id)_parser
++  contentTypeOfPart:(id<NGMimePart>)_part
++{
++  return [NGMimeType mimeType: @"text/plain; charset=utf-8"];
++}
++
+ @end /* WOHttpAdaptor */
+ @implementation WOCoreApplication(SimpleParserSelection)
index eea913c2bf5ec8513719ee7ee8edefde8768ea99..f39aa7f6b1e98a52b3671a9d9e0ef42ea7efb128 100644 (file)
@@ -185,6 +185,7 @@ static BOOL useAltNamespace = NO;
   rawFolders = [[self imap4Connection]
                 allFoldersForURL: [self imap4URL]];
 
+#warning FIXME: the folder names should be prefixed
   mainFolders = [NSArray arrayWithObjects: inboxFolderName, draftsFolderName,
                         sentFolder, trashFolder, nil];
   newFolders = [NSMutableArray arrayWithArray: rawFolders];
index 89d8c68d6653f75d132e11d82ec79f3719d084c3..3cd98c20a6ecf746731a98dfb13b2366a32625f0 100644 (file)
   NSDictionary *mailboxACL;
 }
 
+- (NSString *) absoluteImap4Name;
+
 /* messages */
 
-- (NSArray *)fetchUIDsMatchingQualifier:(id)_q sortOrdering:(id)_so;
-- (NSArray *)fetchUIDs:(NSArray *)_uids parts:(NSArray *)_parts;
+- (NSArray *) fetchUIDsMatchingQualifier: (id)_q sortOrdering: (id) _so;
+- (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts;
 
-- (NSException *)postData:(NSData *)_data flags:(id)_flags;
+- (NSException *) postData: (NSData *) _data flags: (id) _flags;
 
-- (NSException *)expunge;
+- (NSException *) expunge;
 
 /* flags */
 
-- (NSException *)addFlagsToAllMessages:(id)_f;
+- (NSException *) addFlagsToAllMessages: (id) _f;
 
 /* folder type */
 
-- (NSString *)outlookFolderClass;
+- (NSString *) outlookFolderClass;
 
 - (NSArray *) subfolders;
-- (NSArray *) subfoldersURL;
+
+- (NSArray *) allFolderPaths;
+- (NSArray *) allFolderURLs;
 
 @end
 
index 892a663c134999ebd87bfdd7be052e3244f49752..bf277fbbc13cf459838fcc1ae072e66dc2365b67 100644 (file)
@@ -106,6 +106,16 @@ static BOOL useAltNamespace = NO;
   return [nameInContainer substringFromIndex: 6];
 }
 
+- (NSString *) absoluteImap4Name
+{
+  NSString *name;
+
+  name = [[self imap4URL] path];
+  if (![name hasSuffix: @"/"])
+    name = [name stringByAppendingString: @"/"];
+
+  return name;
+}
 
 - (NSMutableString *) imap4URLString
 {
@@ -129,25 +139,45 @@ static BOOL useAltNamespace = NO;
   return [[self imap4Connection] subfoldersForURL: [self imap4URL]];
 }
 
-- (NSArray *) subfoldersURL
+- (NSArray *) allFolderPaths
+{
+  NSMutableArray *deepSubfolders;
+  NSEnumerator *folderNames;
+  NSArray *result;
+  NSString *currentFolderName, *prefix;
+
+  deepSubfolders = [NSMutableArray new];
+  [deepSubfolders autorelease];
+
+  prefix = [self absoluteImap4Name];
+
+  result = [[self mailAccountFolder] allFolderPaths];
+  folderNames = [result objectEnumerator];
+  while ((currentFolderName = [folderNames nextObject]))
+    if ([currentFolderName hasPrefix: prefix])
+      [deepSubfolders addObject: currentFolderName];
+  [deepSubfolders sortUsingSelector: @selector (compare:)];
+
+  return deepSubfolders;
+}
+
+- (NSArray *) allFolderURLs
 {
   NSURL *selfURL, *currentURL;
   NSMutableArray *subfoldersURL;
   NSEnumerator *subfolders;
-  NSString *selfPath, *currentFolder;
+  NSString *currentFolder;
 
   subfoldersURL = [NSMutableArray array];
   selfURL = [self imap4URL];
-  selfPath = [selfURL path];
-  subfolders = [[self subfolders] objectEnumerator];
+  subfolders = [[self allFolderPaths] objectEnumerator];
   currentFolder = [subfolders nextObject];
   while (currentFolder)
     {
       currentURL = [[NSURL alloc]
                     initWithScheme: [selfURL scheme]
                     host: [selfURL host]
-                    path: [selfPath stringByAppendingPathComponent:
-                                      currentFolder]];
+                    path: currentFolder];
       [currentURL autorelease];
       [subfoldersURL addObject: currentURL];
       currentFolder = [subfolders nextObject];
index 255db3b6506c29db6b481f02131c7853a1ca30a8..00ed0779e7d23628b25babdd713f71db8fc15b10 100644 (file)
        }
       if ([containerAcls containsObject: SOGoRole_ObjectReader])
        [acls addObject: SOGoRole_ObjectViewer];
+      if ([containerAcls containsObject: SOGoRole_ObjectEditor])
+       [acls addObject: SOGoRole_ObjectEditor];
     }
 
   return acls;
index 28697447645fb8a41052af2ee7d8d32db3742034..4ff6d1e2352c683a3f90d44991b0831ebc8f0d3c 100644 (file)
@@ -259,23 +259,24 @@ static NSString *defaultUserID = @"<default>";
 
 - (void) sendFolderAdvisoryTemplate: (NSString *) template
 {
-  NSString *language, *pageName;
+  NSString *pageName;
   SOGoUser *user;
   SOGoFolderAdvisory *page;
-  WOApplication *app;
 
-  user = [SOGoUser userWithLogin: [[context activeUser] login] roles: nil];
-  language = [user language];
+  user = [context activeUser];
   pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
-                      language, template];
+                      [user language], template];
 
-  app = [WOApplication application];
-  page = [app pageWithName: pageName inContext: context];
+  page = [[WOApplication application] pageWithName: pageName
+                                     inContext: context];
   [page setFolderObject: self];
-  [page setRecipientUID: [[context activeUser] login]];
+  [page setRecipientUID: [user login]];
   [page send];
 }
 
+
+//   if (!result) [self sendFolderAdvisoryTemplate: @"Addition"];
+
 - (BOOL) create
 {
   NSException *result;
@@ -284,8 +285,6 @@ static NSString *defaultUserID = @"<default>";
                                 withName: displayName
                                  atPath: ocsPath];
 
-  if (!result) [self sendFolderAdvisoryTemplate: @"Addition"];
-
   return (result == nil);
 }
 
@@ -302,11 +301,11 @@ static NSString *defaultUserID = @"<default>";
   else
     error = [[self folderManager] deleteFolderAtPath: ocsPath];
 
-  if (!error) [self sendFolderAdvisoryTemplate: @"Removal"];
-
   return error;
 }
 
+//   if (!error) [self sendFolderAdvisoryTemplate: @"Removal"];
+
 - (void) renameTo: (NSString *) newName
 {
   GCSChannelManager *cm;
index cf14bf58d65518fef06c0d7d5e1341158621b99b..2574e487734ecb2e76d994e229730f01e49e5fda 100644 (file)
 = "Moving a message into its own folder is impossible!";
 "Copying a message into its own folder is impossible!"
 = "Copying a message into its own folder is impossible!";
+
+/* Message editing */
+"error_validationfailed" = "Validation failed";
+"error_missingsubject" = "Subject is missing";
+"error_missingrecipients" = "No recipients specified";
index b68ab6bb3e641b18269b59863b15a761291acb63..6c805eaa18c29670914f7a1c3300c6cb9fcbeebf 100644 (file)
 = "Le déplacement d'un message dans son propre dossier est impossible.";
 "Copying a message into its own folder is impossible!"
 = "La copie d'un message dans son propre dossier est impossible.";
+
+/* Message editing */
+"error_validationfailed" = "Message invalide";
+"error_missingsubject" = "- le sujet est manquant";
+"error_missingrecipients" = "- aucun destinataire spécifié";
index 31b91fe6bb2c46bbfb872b911ee641f2227405fe..40d826d2f2f1b483631a8390f8404f80533ba2be 100644 (file)
 = "Moving a message into its own folder is impossible!";
 "Copying a message into its own folder is impossible!"
 = "Copying a message into its own folder is impossible!";
+
+/* Message editing */
+"error_validationfailed" = "Validation failed";
+"error_missingsubject" = "Subject is missing";
+"error_missingrecipients" = "No recipients specified";
index 7b6d9e13e9dd1bff90cab7878777d000d5fab98e..4e962e432a08bc0fd998503c60131d6a0b3739f2 100644 (file)
@@ -20,6 +20,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#import <Foundation/NSArray.h>
 #import <Foundation/NSString.h>
 
 #import <NGObjWeb/WOContext.h>
   return response;
 }
 
+- (WOResponse *) _addLabel: (unsigned int) number
+{
+  WOResponse *response;
+  SOGoMailObject *co;
+  NSException *error;
+  NSArray *flags;
+
+  co = [self clientObject];
+  flags = [NSArray arrayWithObject:
+                    [NSString stringWithFormat: @"$Label%u", number]];
+  error = [co addFlags: flags];
+  if (error)
+    response = (WOResponse *) error;
+  else
+    response = [self responseWith204];
+
+  return response;
+}
+
+- (WOResponse *) _removeLabel: (unsigned int) number
+{
+  WOResponse *response;
+  SOGoMailObject *co;
+  NSException *error;
+  NSArray *flags;
+
+  co = [self clientObject];
+  flags = [NSArray arrayWithObject:
+                    [NSString stringWithFormat: @"$Label%u", number]];
+  error = [co removeFlags: flags];
+  if (error)
+    response = (WOResponse *) error;
+  else
+    response = [self responseWith204];
+
+  return response;
+}
+
+- (WOResponse *) addLabel1Action
+{
+  return [self _addLabel: 1];
+}
+
+- (WOResponse *) addLabel2Action
+{
+  return [self _addLabel: 2];
+}
+
+- (WOResponse *) addLabel3Action
+{
+  return [self _addLabel: 3];
+}
+
+- (WOResponse *) addLabel4Action
+{
+  return [self _addLabel: 4];
+}
+
+- (WOResponse *) addLabel5Action
+{
+  return [self _addLabel: 5];
+}
+
+- (WOResponse *) removeLabel1Action
+{
+  return [self _removeLabel: 1];
+}
+
+- (WOResponse *) removeLabel2Action
+{
+  return [self _removeLabel: 2];
+}
+
+- (WOResponse *) removeLabel3Action
+{
+  return [self _removeLabel: 3];
+}
+
+- (WOResponse *) removeLabel4Action
+{
+  return [self _removeLabel: 4];
+}
+
+- (WOResponse *) removeLabel5Action
+{
+  return [self _removeLabel: 5];
+}
+
+- (WOResponse *) removeAllLabelsAction
+{
+  WOResponse *response;
+  SOGoMailObject *co;
+  NSException *error;
+  NSArray *flags;
+
+  co = [self clientObject];
+  flags = [NSArray arrayWithObjects: @"$Label1", @"$Label2", @"$Label3",
+                  @"$Label4", @"$Label5", nil];
+  error = [co removeFlags: flags];
+  if (error)
+    response = (WOResponse *) error;
+  else
+    response = [self responseWith204];
+
+  return response;
+}
+
 @end
index ade6ed8d22debadc13b93e18caf0c8ad225fb521..c78fade8b4cb95a61f6522c9d0083261e3fffa7e 100644 (file)
     {
       [co flushMailCaches];
       connection = [co imap4Connection];
-      subfolders = [[co subfoldersURL] objectEnumerator];
+      subfolders = [[co allFolderURLs] objectEnumerator];
       currentURL = [subfolders nextObject];
       while (currentURL)
        {
index e004eae938c26ab6715bb6fa0136d0f331f31232..e2cb26daf9f2580e865a98f56e8a665da3359c7c 100644 (file)
@@ -534,6 +534,23 @@ static int attachmentFlagSize = 8096;
   return [self redirectToLocation:@"view"];
 }
 
+- (NSString *) msgLabels
+{
+  NSMutableArray *labels;
+  NSEnumerator *flags;
+  NSString *currentFlag;
+
+  labels = [NSMutableArray new];
+  [labels autorelease];
+
+  flags = [[message objectForKey: @"flags"] objectEnumerator];
+  while ((currentFlag = [flags nextObject]))
+    if ([currentFlag hasPrefix: @"$label"])
+      [labels addObject: [currentFlag substringFromIndex: 1]];
+
+  return [labels componentsJoinedByString: @" "];
+}
+
 @end
 
 /* UIxMailListView */
index 083bbe4030a5b850c993175e7482008b76e70381..6f269fb35146e5089ae5fd0a291152c0efed5876 100644 (file)
          actionClass = "UIxMailActions";
          actionName  = "markMessageRead";
        };
+       addLabel1 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "addLabel1";
+       };
+       addLabel2 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "addLabel2";
+       };
+       addLabel3 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "addLabel3";
+       };
+       addLabel4 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "addLabel4";
+       };
+       addLabel5 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "addLabel5";
+       };
+       removeLabel1 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeLabel1";
+       };
+       removeLabel2 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeLabel2";
+       };
+       removeLabel3 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeLabel3";
+       };
+       removeLabel4 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeLabel4";
+       };
+       removeLabel5 = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeLabel5";
+       };
+       removeAllLabels = {
+         protectedBy = "View";
+         actionClass = "UIxMailActions";
+         actionName  = "removeAllLabels";
+       };
       };
     };
 
index 11e282820b77922947abc5274e8c39ab2951139c..9c0bba206c94bf5050f0de0f326b9f35c3411f63 100644 (file)
@@ -34,6 +34,8 @@
       protectedBy = "Access Object";
       defaultRoles = {
        "Access Object" = ( "Owner", "ObjectViewer" );
+       "Access Contents Information" = ( "Owner", "ObjectViewer" );
+       "Change Images And Files"  = ( "Owner", "ObjectEditor" );
       };
     };
     SOGoFolder = {
index 8e92f86d5de3d26df9648c6d48c5f31e1d697c2c..8f771dedab9d5a0a934a8aa1077a18dc4cfc8a5c 100644 (file)
@@ -6,7 +6,7 @@
     xmlns:label="OGo:label"
     >
     <div class="menu" id="searchMenu">
-      <ul id="searchOptions">
+      <ul id="searchOptions" class="choiceMenu">
         <li id="name_or_address"><var:string
            label:value="Name or Email"/></li>
       </ul>
index 5d15e65da560386d550dc1e32c837901862ef994..16f79f5450cf8d417b6042544839d151821381e2 100644 (file)
@@ -6,7 +6,7 @@
     xmlns:label="OGo:label"
     >
     <div class="menu" id="searchMenu">
-      <ul id="searchOptions">
+      <ul id="searchOptions" class="choiceMenu">
         <li id="subject"><var:string label:value="Subject"/></li>
         <li id="sender"><var:string label:value="Sender"/></li>
         <li id="subject_or_sender"><var:string
index 09dbd6b6fadb0bbd250bfa6c5f18c60994986c2e..cae21ceb320639d5d26e3b13790b09efea6ea321 100644 (file)
   </thead>
   <tbody>
     <var:foreach list="messages" item="message"
-      ><tr var:class="messageRowStyleClass" var:id="msgRowID"
+      ><tr var:class="messageRowStyleClass" var:id="msgRowID" var:labels="msgLabels"
        ><td class="messageFlagColumn"><var:entity name="nbsp"/></td
          ><td class="messageFlagColumn"
          ><var:if condition="hasMessageAttachment"
            ><img rsrc:src="title_attachment_14x14.png"
              /></var:if
            ></td
-         
          ><td
          var:class="messageSubjectCellStyleClass"
          var:id="msgDivID"
index 8f5012c92ba9c3bd7cc9b595cd3cee56533fe198..d222204db084fe49e9d04978e48cf74ea7c017a6 100644 (file)
   </div>
 
   <div class="menu" id="label-menu">
-    <ul id="">
+    <ul id="" class="choiceMenu">
       <li><var:string label:value="None" /></li>
       <li><!-- separator --></li>
-      <li><var:string label:value="Important" /></li>
-      <li><var:string label:value="Work" /></li>
-      <li><var:string label:value="Personal" /></li>
-      <li><var:string label:value="To Do" /></li>
-      <li><var:string label:value="Later" /></li>
+      <li class="label1"><var:string label:value="Important" /></li>
+      <li class="label2"><var:string label:value="Work" /></li>
+      <li class="label3"><var:string label:value="Personal" /></li>
+      <li class="label4"><var:string label:value="To Do" /></li>
+      <li class="label5"><var:string label:value="Later" /></li>
     </ul>
   </div>
 
index c0b6f513be6e33649e179f4d5a325e1b15dc3af9..05a9ad293bbebf10b904cc4738479417b1ecf27f 100644 (file)
@@ -6,7 +6,7 @@
     xmlns:label="OGo:label"
     >
     <div class="menu" id="searchMenu">
-      <ul id="searchOptions">
+      <ul id="searchOptions" class="choiceMenu">
         <li><var:string label:value="Title or Description"/></li>
       </ul>
     </div>
index 52caee9cb1b83f7459fa17307d7469c825acd4a4..16ad19fcd8712ba4399b059332a5b83e3ea7a010 100644 (file)
@@ -19,7 +19,7 @@
   </script>
 
   <div class="menu" id="privacy-menu">
-    <ul id="itemPrivacyList">
+    <ul id="itemPrivacyList" class="choiceMenu">
       <var:foreach list="privacyClasses" item="item">
        <li var:classification="item"><var:string
            var:value="itemPrivacyText" /></li>
index 1b6a5204276d6e7f20176a8848a66b495b04039e..abd9a6ec1487fe3eb968081b0e68b9509d1487f0 100644 (file)
@@ -90,6 +90,21 @@ DIV#folderTreeContent
   bottom: 0px;
   overflow: auto; }
 
+#label-menu LI.label1
+{ color: #f00; }
+
+#label-menu LI.label2
+{ color: #ff9a00; }
+
+#label-menu LI.label3
+{ color: #009a00; }
+
+#label-menu LI.label4
+{ color: #3130ff; }
+
+#label-menu LI.label5
+{ color: #9c309c; }
+
 .aptview_title
 {
   color: #000000;
@@ -368,6 +383,12 @@ DIV.mailer_plaincontent
   position: relative;
   font-family: monospace, fixed;
   white-space: pre;
+  white-space: pre-wrap;                  /* css-3 */
+  white-space: -moz-pre-wrap !important;  /* Mozilla, since 1999 */
+  white-space: -pre-wrap;                 /* Opera 4-6 */
+  white-space: -o-pre-wrap;               /* Opera 7 */
+  word-wrap: break-word;                  /* Internet Explorer 5.5+ */
+  width: 99%;
   font-size: inherit;
   margin: 0px;
   padding: 0px;
@@ -512,7 +533,7 @@ TABLE#messageList TD.tbtv_date_headercell
 
 TABLE#messageList TR._selected TD
 { 
-  background: #4b6983;
+  background-color: #4b6983;
   color: #fff;
 }
 
@@ -521,6 +542,41 @@ TABLE#messageList TR._deleted TD
   text-decoration: line-through;
 }
 
+TABLE#messageList TR[labels~="label5"] TD
+{ color: #9c309c; }
+
+TABLE#messageList TR[labels~="label5"]._selected TD
+{ color: #fff;
+  background-color: #9c309c; }
+
+TABLE#messageList TR[labels~="label4"] TD
+{ color: #3130ff; }
+
+TABLE#messageList TR[labels~="label4"]._selected TD
+{ color: #fff;
+  background-color: #3130ff; }
+
+TABLE#messageList TR[labels~="label3"] TD
+{ color: #009a00; }
+
+TABLE#messageList TR[labels~="label3"]._selected TD
+{ color: #fff;
+  background-color: #009a00; }
+
+TABLE#messageList TR[labels~="label2"] TD
+{ color: #ff9a00; }
+
+TABLE#messageList TR[labels~="label2"]._selected TD
+{ color: #fff;
+  background-color: #ff9a00; }
+
+TABLE#messageList TR[labels~="label1"] TD
+{ color: #f00; }
+
+TABLE#messageList TR[labels~="label1"]._selected TD
+{ color: #fff;
+  background-color: #f00; }
+
 /* drag handles */
 DIV#verticalDragHandle
 {
index 105f96ba1d80793035843114b1915a4515d5ca33..2e086b91f0dd2692e6ffa78273cd3de0211cc59c 100644 (file)
@@ -988,8 +988,6 @@ var messageListData = function(type) {
 }
 
 /* a model for a futur refactoring of the sortable table headers mechanism */
-
-
 function configureMessageListEvents(table) {
   if (table) {
     table.multiselect = true;
@@ -1379,6 +1377,50 @@ function onMenuChangeToTrashFolder(event) {
   return _onMenuChangeToXXXFolder(event, "Trash");
 }
 
+function onMenuLabelNone() {
+  var rowId = document.menuTarget.getAttribute("id").substr(4);
+  var messageId = currentMailbox + "/" + rowId;
+  var urlstr = ApplicationBaseURL + messageId + "/removeAllLabels";
+  triggerAjaxRequest(urlstr, messageFlagCallback,
+                    { mailbox: currentMailbox, msg: rowId, label: null } );
+}
+
+function _onMenuLabelFlagX(flag) {
+  var flags = document.menuTarget.getAttribute("labels").split(" ");
+
+  var rowId = document.menuTarget.getAttribute("id").substr(4);
+  var messageId = currentMailbox + "/" + rowId;
+
+  var operation = "add";
+  if (flags.indexOf("label" + flag) > -1)
+    operation = "remove";
+  var urlstr = (ApplicationBaseURL + messageId
+               + "/" + operation + "Label" + flag);
+  triggerAjaxRequest(urlstr, messageFlagCallback,
+                    { mailbox: currentMailbox, msg: rowId,
+                      label: operation + flag } );
+}
+
+function onMenuLabelFlag1() {
+  _onMenuLabelFlagX(1);
+}
+
+function onMenuLabelFlag2() {
+  _onMenuLabelFlagX(2);
+}
+
+function onMenuLabelFlag3() {
+  _onMenuLabelFlagX(3);
+}
+
+function onMenuLabelFlag4() {
+  _onMenuLabelFlagX(4);
+}
+
+function onMenuLabelFlag5() {
+  _onMenuLabelFlagX(5);
+}
+
 function folderOperationCallback(http) {
   if (http.readyState == 4
       && isHttpStatus204(http.status))
@@ -1398,6 +1440,65 @@ function folderRefreshCallback(http) {
     window.alert(labels["Operation failed"]);
 }
 
+function messageFlagCallback(http) {
+  if (http.readyState == 4
+      && isHttpStatus204(http.status)) {
+    var data = http.callbackData;
+    if (data["mailbox"] == currentMailbox) {
+      var row = $("row_" + data["msg"]);
+      var operation = data["label"];
+      if (operation) {
+       var labels = row.getAttribute("labels");
+       var flags;
+       if (labels.length > 0)
+         flags = labels.split(" ");
+       else
+         flags = new Array();
+       if (operation.substr(0, 3) == "add")
+         flags.push("label" + operation.substr(3));
+       else {
+         var flag = "label" + operation.substr(6);
+         var idx = flags.indexOf(flag);
+         flags.splice(idx, 1);
+       }
+       row.setAttribute("labels", flags.join(" "));
+      }
+      else
+       row.setAttribute("labels", "");
+    }
+  }
+}
+
+function onLabelMenuPrepareVisibility() {
+  var messageList = $("messageList");
+  var rows = messageList.getSelectedRows();
+
+  var flags = {};
+  for (var i = 1; i < 6; i++)
+    flags["label" + i] = true;
+  for (var i = 0; i < rows.length; i++) {
+    var rowFlags = rows[i].getAttribute("labels").split(" ");
+    for (var flag in flags)
+      if (flags[flag] && rowFlags.indexOf(flag) == -1)
+       flags[flag] = false;
+  }
+
+  var lis = this.childNodesWithTag("ul")[0].childNodesWithTag("li")
+  var isFlagged = false;
+  for (var i = 1; i < 6; i++) {
+    if (flags["label" + i]) {
+      isFlagged = true;
+      lis[1 + i].addClassName("_chosen");
+    }
+    else
+      lis[1 + i].removeClassName("_chosen");
+  }
+  if (isFlagged)
+    lis[0].removeClassName("_chosen");
+  else
+    lis[0].addClassName("_chosen");
+}
+
 function getMenus() {
   var menus = {}
   menus["accountIconMenu"] = new Array(null, null, onMenuCreateFolder, null,
@@ -1441,14 +1542,16 @@ function getMenus() {
   menus["folderTypeMenu"] = new Array(onMenuChangeToSentFolder,
                                      onMenuChangeToDraftsFolder,
                                      onMenuChangeToTrashFolder);
-  
-  menus["label-menu"] = new Array(null, "-", null , null, null, null , null,
-                                 null);
+
+  menus["label-menu"] = new Array(onMenuLabelNone, "-", onMenuLabelFlag1,
+                                 onMenuLabelFlag2, onMenuLabelFlag3,
+                                 onMenuLabelFlag4, onMenuLabelFlag5);
   menus["mark-menu"] = new Array(null, null, null, null, "-", null, "-",
                                 null, null, null);
   menus["searchMenu"] = new Array(setSearchCriteria, setSearchCriteria,
                                  setSearchCriteria, setSearchCriteria,
                                  setSearchCriteria);
+  $("label-menu").prepareVisibility = onLabelMenuPrepareVisibility;
 
   return menus;
 }
index c52611a32c832536e2f679c871a5b9e94d31e90d..1528f4688c41e3f459af933713ebb96130524690 100644 (file)
@@ -13,16 +13,6 @@ DIV.appointmentRightLabel
 { display: inline;
   vertical-align: middle; }
 
-#privacy-menu LI
-{ list-style-position: inside;
-  list-style-image: url("menu-nocheck.gif"); }
-
-#privacy-menu LI._chosen
-{ list-style-image: url("menu-check.gif"); }
-
-#privacy-menu LI._chosen:hover
-{ list-style-image: url("menu-check-hover.gif"); }
-
 UL.contactList
 { display: block;
   cursor: default;
index 2fdc38526ebb7a8065b0af8f508dc45de7adaa33..5e94ed0b2e0005fdbebd303910da6b855101ad6b 100644 (file)
@@ -126,15 +126,16 @@ function validateEditorInput(sender) {
    
    field = document.pageform.subject;
    if (field.value == "")
-      errortext = errortext + labels.error_missingsubject + "\n";
+      errortext = errortext + labels["error_missingsubject"] + "\n";
 
    if (!UIxRecipientSelectorHasRecipients())
-      errortext = errortext + labels.error_missingrecipients + "\n";
+      errortext = errortext + labels["error_missingrecipients"] + "\n";
    
    if (errortext.length > 0) {
-      alert(labels.error_validationfailed + ":\n" + errortext);
+      alert(labels["error_validationfailed"] + ":\n" + errortext);
       return false;
    }
+
    return true;
 }
 
@@ -337,7 +338,7 @@ function onMailEditorClose(event) {
     http.open("POST", url, false /* not async */);
     http.send("");
   }
-  
+
   Event.stopObserving(window, "beforeunload", onMailEditorClose);
 }
 
index 4e32017281721274ff7fb599ec2e81b5e9b714a1..ec02c5e111e32b6b53050a24ba293cfb8d61b108 100644 (file)
@@ -13,16 +13,6 @@ DIV.appointmentRightLabel
 { display: inline;
   vertical-align: middle; }
 
-#privacy-menu LI
-{ list-style-position: inside;
-  list-style-image: url("menu-nocheck.gif"); }
-
-#privacy-menu LI._chosen
-{ list-style-image: url("menu-check.gif"); }
-
-#privacy-menu LI._chosen:hover
-{ list-style-image: url("menu-check-hover.gif"); }
-
 LABEL, SPAN.checkBoxList
 { display: block;
   position: relative;
index a8e6e15223d9014ca1143df83786d8dfdf77917b..b33b6dee8eaee9e0348e67e561c1af4b24d0ef45 100644 (file)
@@ -285,6 +285,7 @@ SPAN.toolbarButton:active
 { margin: auto; }
 
 /* popups */
+
 .menu
 { visibility: hidden;
   position: absolute;
@@ -327,6 +328,20 @@ SPAN.toolbarButton:active
   padding-right: .2em;
   vertical-align: middle; }
 
+/* popup menu with check marks */
+UL.choiceMenu LI
+{ list-style-position: inside;
+  list-style-image: url("menu-nocheck.gif");
+  padding: 3px 3px;
+  margin: 0px;
+  padding-right: 10px; }
+
+UL.choiceMenu LI._chosen
+{ list-style-image: url("menu-check.gif"); }
+
+UL.choiceMenu LI._chosen:hover
+{ list-style-image: url("menu-check-hover.gif"); }
+
 .menu LI:hover, .menu LI.submenu-selected
 { background-color: #4b6983;
   color: #fff; }
@@ -352,19 +367,6 @@ SPAN.toolbarButton:active
 .menu LI.submenu:hover, .menu LI.submenu-selected
 { background-image: url('submenu-active.gif') !important; }
 
-/* live search popup menu */
-UL#searchOptions LI
-{ list-style-position: inside;
-  list-style-image: url("menu-nocheck.gif");
-  padding: 1px 3px;
-  margin: 0px; }
-
-UL#searchOptions LI._chosen
-{ list-style-image: url("menu-check.gif"); }
-
-UL#searchOptions LI._chosen:hover
-{ list-style-image: url("menu-check-hover.gif"); }
-
 DIV#logConsole
 { position: absolute;
   overflow: auto;
index 4522d2d085e70debf7e62ffbd9092b32ce42c742..68a5d49148bd2ba0a3af1be48b526c32f61443cb 100644 (file)
@@ -585,9 +585,11 @@ function popupMenu(event, menuId, target) {
   if (leftDiff < 0)
     menuLeft -= popup.offsetWidth;
 
+  if (popup.prepareVisibility)
+    popup.prepareVisibility();
   popup.setStyle({ top: menuTop + "px",
-       left: menuLeft + "px",
-       visibility: "visible" });
+                  left: menuLeft + "px",
+                  visibility: "visible" });
 
   document.currentPopupMenu = popup;
 
@@ -614,7 +616,7 @@ function getParentMenu(node) {
 }
 
 function onBodyClickMenuHandler(event) {
-  document.body.menuTarget = null;
+  document.menuTarget = null;
   hideMenu(document.currentPopupMenu);
   Event.stopObserving(document.body, "click", onBodyClickMenuHandler);
 
@@ -776,6 +778,9 @@ function popupSubmenu(event) {
     parentNode.submenuItem = this;
     parentNode.submenu = submenuNode;
 
+    if (submenuNode.prepareVisibility)
+      submenuNode.prepareVisibility();
+
     var menuTop = (parentNode.offsetTop - 1
                   + this.offsetTop);
     if (window.height()