From ae565d508afc970569dd8a9bf14af0015f169f24 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Wed, 5 Dec 2007 22:25:00 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1288 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 21 + Main/GNUmakefile | 2 +- Main/NSException+Stacktrace.m | 889 ++++++++++++++++++ SoObjects/Mailer/SOGoDraftObject.m | 42 +- SoObjects/SOGo/SOGoUserFolder.m | 12 +- UI/Contacts/UIxContactFoldersView.m | 115 --- UI/Contacts/product.plist | 5 - UI/MainUI/SOGoRootPage.m | 1 + UI/MainUI/SOGoUserHomePage.m | 83 ++ UI/MainUI/product.plist | 5 + UI/WebServerResources/MailerUI.css | 3 +- UI/WebServerResources/MailerUI.js | 12 +- UI/WebServerResources/SchedulerUI.js | 47 +- .../UIxContactsUserFolders.js | 19 +- UI/WebServerResources/UIxMailToSelection.js | 14 +- UI/WebServerResources/generic.js | 14 +- 16 files changed, 1080 insertions(+), 204 deletions(-) create mode 100644 Main/NSException+Stacktrace.m diff --git a/ChangeLog b/ChangeLog index 37b7b4ae..efbbf3bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2007-12-05 Wolfgang Sourdeau + + * Main/NSException+Stacktrace.m: added missing symbols from + NSException.m and NSDebug.m (GNUstep). + + * UI/MainUI/SOGoUserHomePage.m ([SOGoUserHomePage + -foldersSearchAction]): make use of the new search methods in + SOGoUserFolder (see below). + + * UI/Contacts/UIxContactFoldersView.m ([-foldersSearchAction]): + moved method into ../MainUI/SOGoUserHomePage.m. + + * SoObjects/SOGo/SOGoUserFolder.m ([SOGoUserFolder + -foldersOfType:folderTypeforUID:uid]): only return folders owned + by the specified user. + +2007-12-05 Francis Lachapelle + + * SoObjects/Mailer/SOGoDraftObject.m: The condition for replyToAll + has to be done later to avoid duplicated to and cc addresses. + 2007-12-04 Wolfgang Sourdeau * SoObjects/Appointments/SOGoAppointmentFolder.m diff --git a/Main/GNUmakefile b/Main/GNUmakefile index cac596f5..ab489728 100644 --- a/Main/GNUmakefile +++ b/Main/GNUmakefile @@ -5,7 +5,7 @@ include $(GNUSTEP_MAKEFILES)/common.make include ../Version include ./Version -ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ +ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -D_GNU_SOURCE ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -lbfd SOGOD = sogod-$(MAJOR_VERSION).$(MINOR_VERSION) diff --git a/Main/NSException+Stacktrace.m b/Main/NSException+Stacktrace.m new file mode 100644 index 00000000..c08bc21a --- /dev/null +++ b/Main/NSException+Stacktrace.m @@ -0,0 +1,889 @@ +/** NSException - Object encapsulation of a general exception handler + Copyright (C) 1993, 1994, 1996, 1997, 1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Mar 1995 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02111 USA. + + $Date: 2007-09-14 07:36:11 -0400 (Fri, 14 Sep 2007) $ $Revision: 25482 $ + + NOTE: This code was taken from GNUstep Base Library and sligthly modified + by Ludovic Marcotte +*/ + +#include +#include +#include + +typedef void* dl_handle_t; +typedef void* dl_symbol_t; + +#import "NSException+Stacktrace.h" + +#import +#import +#import +#import +#import +#import +#import + +// #if GNUSTEP_BASE_MAJOR_VERSION >= 1 +// #if GNUSTEP_BASE_MINOR_VERSION > 13 + +// +// +// +static void _terminate() +{ + abort(); +} + +static void +_NSFoundationUncaughtExceptionHandler (NSException *exception) +{ + NSString *stack; + + fprintf(stderr, "Uncaught exception %s, reason: %s\n", + [[exception name] lossyCString], [[exception reason] lossyCString]); + fflush(stderr); /* NEEDED UNDER MINGW */ + stack = [[[exception userInfo] objectForKey: @"GSStackTraceKey"] description]; + if (stack != nil) + { + fprintf(stderr, "Stack\n%s\n", [stack lossyCString]); + } + fflush(stderr); /* NEEDED UNDER MINGW */ + + _terminate(); +} + +// +// +// + +#define STACKSYMBOLS 1 + +@interface GSStackTrace : NSObject +{ + NSMutableArray *frames; +} + ++ (GSStackTrace*) currentStack; + +- (NSString*) description; +- (NSEnumerator*) enumerator; +- (id) frameAt: (unsigned)index; +- (unsigned) frameCount; +- (NSEnumerator*) reverseEnumerator; + +@end + +#ifdef STACKSYMBOLS + +// GSStackTrace inspired by FYStackTrace.m +// created by Wim Oudshoorn on Mon 11-Apr-2006 +// reworked by Lloyd Dupont @ NovaMind.com on 4-May-2006 + +@class GSBinaryFileInfo; + +@interface GSFunctionInfo : NSObject +{ + void *_address; + NSString *_fileName; + NSString *_functionName; + int _lineNo; + GSBinaryFileInfo *_module; +} +- (void*) address; +- (NSString *) fileName; +- (NSString *) function; +- (id) initWithModule: (GSBinaryFileInfo*)module + address: (void*)address + file: (NSString*)file + function: (NSString*)function + line: (int)lineNo; +- (int) lineNumber; +- (GSBinaryFileInfo*) module; + +@end + + +@interface GSBinaryFileInfo : NSObject +{ + NSString *_fileName; + bfd *_abfd; + asymbol **_symbols; + long _symbolCount; +} +- (NSString *) fileName; +- (GSFunctionInfo *) functionForAddress: (void*) address; +- (id) initWithBinaryFile: (NSString *)fileName; +- (id) init; // return info for the current executing process + +@end + +@implementation GSFunctionInfo + +- (void*) address +{ + return _address; +} + +- (oneway void) dealloc +{ + [_module release]; + _module = nil; + [_fileName release]; + _fileName = nil; + [_functionName release]; + _functionName = nil; + [super dealloc]; +} + +- (NSString *) description +{ + return [NSString stringWithFormat: @"(%@: %p) %@ %@: %d", + [_module fileName], _address, _functionName, _fileName, _lineNo]; +} + +- (NSString *) fileName +{ + return _fileName; +} + +- (NSString *) function +{ + return _functionName; +} + +- (id) init +{ + [self release]; + return nil; +} + +- (id) initWithModule: (GSBinaryFileInfo*)module + address: (void*)address + file: (NSString*)file + function: (NSString*)function + line: (int)lineNo +{ + _module = [module retain]; + _address = address; + _fileName = [file retain]; + _functionName = [function retain]; + _lineNo = lineNo; + + return self; +} + +- (int) lineNumber +{ + return _lineNo; +} + +- (GSBinaryFileInfo *) module +{ + return _module; +} + +@end + +@implementation GSBinaryFileInfo + ++ (GSBinaryFileInfo*) infoWithBinaryFile: (NSString *)fileName +{ + return [[[self alloc] initWithBinaryFile: fileName] autorelease]; +} + ++ (void) initialize +{ + static BOOL first = YES; + + if (first == NO) + { + return; + } + first = NO; + bfd_init (); +} + +- (oneway void) dealloc +{ + [_fileName release]; + _fileName = nil; + if (_abfd) + { + bfd_close (_abfd); + _abfd = NULL; + } + if (_symbols) + { + objc_free (_symbols); + _symbols = NULL; + } + [super dealloc]; +} + +- (NSString *) fileName +{ + return _fileName; +} + +- (id) init +{ + NSString *processName; + + processName = [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0]; + return [self initWithBinaryFile: processName]; +} + +- (id) initWithBinaryFile: (NSString *)fileName +{ + int neededSpace; + + // 1st initialize the bfd + if ([fileName length] == 0) + { + //NSLog (@"GSBinaryFileInfo: No File"); + [self release]; + return nil; + } + _fileName = [fileName copy]; + _abfd = bfd_openr ([fileName cString], NULL); + if (!_abfd) + { + //NSLog (@"GSBinaryFileInfo: No Binary Info"); + [self release]; + return nil; + } + if (!bfd_check_format_matches (_abfd, bfd_object, NULL)) + { + //NSLog (@"GSBinaryFileInfo: BFD format object error"); + [self release]; + return nil; + } + + // second read the symbols from it + if (!(bfd_get_file_flags (_abfd) & HAS_SYMS)) + { + //NSLog (@"GSBinaryFileInfo: BFD does not contain any symbols"); + [self release]; + return nil; + } + + neededSpace = bfd_get_symtab_upper_bound (_abfd); + if (neededSpace < 0) + { + //NSLog (@"GSBinaryFileInfo: BFD error while deducing needed space"); + [self release]; + return nil; + } + if (neededSpace == 0) + { + //NSLog (@"GSBinaryFileInfo: BFD no space for symbols needed"); + [self release]; + return nil; + } + _symbols = objc_malloc (neededSpace); + if (!_symbols) + { + //NSLog (@"GSBinaryFileInfo: Can't allocate buffer"); + [self release]; + return nil; + } + _symbolCount = bfd_canonicalize_symtab (_abfd, _symbols); + if (_symbolCount < 0) + { + //NSLog (@"GSBinaryFileInfo: BFD error while reading symbols"); + [self release]; + return nil; + } + + return self; +} + +struct SearchAddressStruct +{ + void *theAddress; + GSBinaryFileInfo *module; + asymbol **symbols; + GSFunctionInfo *theInfo; +}; + +static void find_address (bfd *abfd, asection *section, + struct SearchAddressStruct *info) +{ + bfd_vma address; + bfd_vma vma; + unsigned size; + const char *fileName; + const char *functionName; + unsigned line = 0; + + if (info->theInfo) + { + return; + } + if (!(bfd_get_section_flags (abfd, section) & SEC_ALLOC)) + { + return; + } + + address = (bfd_vma) (intptr_t)info->theAddress; + + vma = bfd_get_section_vma (abfd, section); + +#if defined(bfd_get_section_size) + size = bfd_get_section_size (section); // recent +#else + size = bfd_section_size (abfd, section); // older version +#endif + + if (address < vma || address >= vma + size) + { + return; + } + + if (bfd_find_nearest_line (abfd, section, info->symbols, + address - vma, &fileName, &functionName, &line)) + { + GSFunctionInfo *fi; + NSString *file = nil; + NSString *func = nil; + + if (fileName != 0) + { + file = [NSString stringWithCString: fileName + encoding: [NSString defaultCStringEncoding]]; + } + if (functionName != 0) + { + func = [NSString stringWithCString: functionName + encoding: [NSString defaultCStringEncoding]]; + } + fi = [GSFunctionInfo alloc]; + fi = [fi initWithModule: info->module + address: info->theAddress + file: file + function: func + line: line]; + [fi autorelease]; + info->theInfo = fi; + } +} + +- (GSFunctionInfo *) functionForAddress: (void*) address +{ + struct SearchAddressStruct searchInfo = { address, self, _symbols, nil }; + + bfd_map_over_sections (_abfd, + (void (*) (bfd *, asection *, void *)) find_address, &searchInfo); + return searchInfo.theInfo; +} + +@end + +static NSRecursiveLock *modLock = nil; +static NSMutableDictionary *stackModules = nil; + +// initialize stack trace info +static id +GSLoadModule(NSString *fileName) +{ + GSBinaryFileInfo *module = nil; + + [modLock lock]; + + if (stackModules == nil) + { + NSEnumerator *enumerator; + NSBundle *bundle; + + stackModules = [NSMutableDictionary new]; + + /* + * Try to ensure we have the main, base and gui library bundles. + */ + [NSBundle mainBundle]; + [NSBundle bundleForClass: [NSObject class]]; + [NSBundle bundleForClass: NSClassFromString(@"NSView")]; + + /* + * Add file info for all bundles with code. + */ + enumerator = [[NSBundle allBundles] objectEnumerator]; + while ((bundle = [enumerator nextObject]) != nil) + { + if ([bundle load] == YES) + { + GSLoadModule([bundle executablePath]); + } + } + } + + if ([fileName length] > 0) + { + module = [stackModules objectForKey: fileName]; + if (module == nil); + { + module = [GSBinaryFileInfo infoWithBinaryFile: fileName]; + if (module == nil) + { + module = (id)[NSNull null]; + } + if ([stackModules objectForKey: fileName] == nil) + { + [stackModules setObject: module forKey: fileName]; + } + else + { + module = [stackModules objectForKey: fileName]; + } + } + } + [modLock unlock]; + + if (module == (id)[NSNull null]) + { + module = nil; + } + return module; +} + +#endif /* STACKSYMBOLS */ + + +// +// +// +@implementation NSException (SOGoExtensions) + +- (void) raise +{ +#ifndef _NATIVE_OBJC_EXCEPTIONS + NSThread *thread; + NSHandler *handler; +#endif + + if ([_e_info objectForKey: @"GSStackTraceKey"] == nil) + { + NSMutableDictionary *m; + + if (_e_info == nil) + { + _e_info = m = [NSMutableDictionary new]; + } + else if ([_e_info isKindOfClass: [NSMutableDictionary class]] == YES) + { + m = (NSMutableDictionary*)_e_info; + } + else + { + m = [_e_info mutableCopy]; + RELEASE(_e_info); + _e_info = m; + } + [m setObject: [GSStackTrace currentStack] forKey: @"GSStackTraceKey"]; + } + +#ifdef _NATIVE_OBJC_EXCEPTIONS + @throw self; +#else + thread = GSCurrentThread(); + handler = thread->_exception_handler; + if (handler == NULL) + { + static int recursion = 0; + + /* + * Set/check a counter to prevent recursive uncaught exceptions. + * Allow a little recursion in case we have different handlers + * being tried. + */ + if (recursion++ > 3) + { + fprintf(stderr, + "recursion encountered handling uncaught exception\n"); + fflush(stderr); /* NEEDED UNDER MINGW */ + _terminate(); + } + + /* + * Call the uncaught exception handler (if there is one). + */ + if (_NSUncaughtExceptionHandler != NULL) + { + (*_NSUncaughtExceptionHandler)(self); + } + + /* + * The uncaught exception handler which is set has not + * exited, so we call the builtin handler, (undocumented + * behavior of MacOS-X). + * The standard handler is guaranteed to exit/abort. + */ + _NSFoundationUncaughtExceptionHandler(self); + } + + thread->_exception_handler = handler->next; + handler->exception = self; + longjmp(handler->jumpState, 1); +#endif +} + +@end + +static jmp_buf * +jbuf() +{ + NSMutableData *d; + + d = [[[NSThread currentThread] threadDictionary] objectForKey: @"GSjbuf"]; + if (d == nil) + { + d = [[NSMutableData alloc] initWithLength: + sizeof(jmp_buf) + sizeof(void(*)(int))]; + [[[NSThread currentThread] threadDictionary] setObject: d + forKey: @"GSjbuf"]; + RELEASE(d); + } + return (jmp_buf*)[d mutableBytes]; +} + +static void +recover(int sig) +{ + jmp_buf *env = jbuf(); + + longjmp(*env, 1); +} + +#define _NS_FRAME_HACK(a) case a: val = __builtin_frame_address(a + 1); break; +#define _NS_RETURN_HACK(a) case a: val = __builtin_return_address(a + 1); break; + +static void * +NSFrameAddress(int offset) +{ + jmp_buf *env; + void (*old)(int); + void *val; + + env = jbuf(); + if (setjmp(*env) == 0) + { + old = signal(SIGSEGV, recover); + memcpy(env + 1, &old, sizeof(old)); + switch (offset) + { + _NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2); + _NS_FRAME_HACK(3); _NS_FRAME_HACK(4); _NS_FRAME_HACK(5); + _NS_FRAME_HACK(6); _NS_FRAME_HACK(7); _NS_FRAME_HACK(8); + _NS_FRAME_HACK(9); _NS_FRAME_HACK(10); _NS_FRAME_HACK(11); + _NS_FRAME_HACK(12); _NS_FRAME_HACK(13); _NS_FRAME_HACK(14); + _NS_FRAME_HACK(15); _NS_FRAME_HACK(16); _NS_FRAME_HACK(17); + _NS_FRAME_HACK(18); _NS_FRAME_HACK(19); _NS_FRAME_HACK(20); + _NS_FRAME_HACK(21); _NS_FRAME_HACK(22); _NS_FRAME_HACK(23); + _NS_FRAME_HACK(24); _NS_FRAME_HACK(25); _NS_FRAME_HACK(26); + _NS_FRAME_HACK(27); _NS_FRAME_HACK(28); _NS_FRAME_HACK(29); + _NS_FRAME_HACK(30); _NS_FRAME_HACK(31); _NS_FRAME_HACK(32); + _NS_FRAME_HACK(33); _NS_FRAME_HACK(34); _NS_FRAME_HACK(35); + _NS_FRAME_HACK(36); _NS_FRAME_HACK(37); _NS_FRAME_HACK(38); + _NS_FRAME_HACK(39); _NS_FRAME_HACK(40); _NS_FRAME_HACK(41); + _NS_FRAME_HACK(42); _NS_FRAME_HACK(43); _NS_FRAME_HACK(44); + _NS_FRAME_HACK(45); _NS_FRAME_HACK(46); _NS_FRAME_HACK(47); + _NS_FRAME_HACK(48); _NS_FRAME_HACK(49); _NS_FRAME_HACK(50); + _NS_FRAME_HACK(51); _NS_FRAME_HACK(52); _NS_FRAME_HACK(53); + _NS_FRAME_HACK(54); _NS_FRAME_HACK(55); _NS_FRAME_HACK(56); + _NS_FRAME_HACK(57); _NS_FRAME_HACK(58); _NS_FRAME_HACK(59); + _NS_FRAME_HACK(60); _NS_FRAME_HACK(61); _NS_FRAME_HACK(62); + _NS_FRAME_HACK(63); _NS_FRAME_HACK(64); _NS_FRAME_HACK(65); + _NS_FRAME_HACK(66); _NS_FRAME_HACK(67); _NS_FRAME_HACK(68); + _NS_FRAME_HACK(69); _NS_FRAME_HACK(70); _NS_FRAME_HACK(71); + _NS_FRAME_HACK(72); _NS_FRAME_HACK(73); _NS_FRAME_HACK(74); + _NS_FRAME_HACK(75); _NS_FRAME_HACK(76); _NS_FRAME_HACK(77); + _NS_FRAME_HACK(78); _NS_FRAME_HACK(79); _NS_FRAME_HACK(80); + _NS_FRAME_HACK(81); _NS_FRAME_HACK(82); _NS_FRAME_HACK(83); + _NS_FRAME_HACK(84); _NS_FRAME_HACK(85); _NS_FRAME_HACK(86); + _NS_FRAME_HACK(87); _NS_FRAME_HACK(88); _NS_FRAME_HACK(89); + _NS_FRAME_HACK(90); _NS_FRAME_HACK(91); _NS_FRAME_HACK(92); + _NS_FRAME_HACK(93); _NS_FRAME_HACK(94); _NS_FRAME_HACK(95); + _NS_FRAME_HACK(96); _NS_FRAME_HACK(97); _NS_FRAME_HACK(98); + _NS_FRAME_HACK(99); + default: val = NULL; break; + } + signal(SIGSEGV, old); + } + else + { + env = jbuf(); + memcpy(&old, env + 1, sizeof(old)); + signal(SIGSEGV, old); + val = NULL; + } + return val; +} + +static void * +NSReturnAddress(int offset) +{ + jmp_buf *env; + void (*old)(int); + void *val; + + env = jbuf(); + if (setjmp(*env) == 0) + { + old = signal(SIGSEGV, recover); + memcpy(env + 1, &old, sizeof(old)); + switch (offset) + { + _NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2); + _NS_RETURN_HACK(3); _NS_RETURN_HACK(4); _NS_RETURN_HACK(5); + _NS_RETURN_HACK(6); _NS_RETURN_HACK(7); _NS_RETURN_HACK(8); + _NS_RETURN_HACK(9); _NS_RETURN_HACK(10); _NS_RETURN_HACK(11); + _NS_RETURN_HACK(12); _NS_RETURN_HACK(13); _NS_RETURN_HACK(14); + _NS_RETURN_HACK(15); _NS_RETURN_HACK(16); _NS_RETURN_HACK(17); + _NS_RETURN_HACK(18); _NS_RETURN_HACK(19); _NS_RETURN_HACK(20); + _NS_RETURN_HACK(21); _NS_RETURN_HACK(22); _NS_RETURN_HACK(23); + _NS_RETURN_HACK(24); _NS_RETURN_HACK(25); _NS_RETURN_HACK(26); + _NS_RETURN_HACK(27); _NS_RETURN_HACK(28); _NS_RETURN_HACK(29); + _NS_RETURN_HACK(30); _NS_RETURN_HACK(31); _NS_RETURN_HACK(32); + _NS_RETURN_HACK(33); _NS_RETURN_HACK(34); _NS_RETURN_HACK(35); + _NS_RETURN_HACK(36); _NS_RETURN_HACK(37); _NS_RETURN_HACK(38); + _NS_RETURN_HACK(39); _NS_RETURN_HACK(40); _NS_RETURN_HACK(41); + _NS_RETURN_HACK(42); _NS_RETURN_HACK(43); _NS_RETURN_HACK(44); + _NS_RETURN_HACK(45); _NS_RETURN_HACK(46); _NS_RETURN_HACK(47); + _NS_RETURN_HACK(48); _NS_RETURN_HACK(49); _NS_RETURN_HACK(50); + _NS_RETURN_HACK(51); _NS_RETURN_HACK(52); _NS_RETURN_HACK(53); + _NS_RETURN_HACK(54); _NS_RETURN_HACK(55); _NS_RETURN_HACK(56); + _NS_RETURN_HACK(57); _NS_RETURN_HACK(58); _NS_RETURN_HACK(59); + _NS_RETURN_HACK(60); _NS_RETURN_HACK(61); _NS_RETURN_HACK(62); + _NS_RETURN_HACK(63); _NS_RETURN_HACK(64); _NS_RETURN_HACK(65); + _NS_RETURN_HACK(66); _NS_RETURN_HACK(67); _NS_RETURN_HACK(68); + _NS_RETURN_HACK(69); _NS_RETURN_HACK(70); _NS_RETURN_HACK(71); + _NS_RETURN_HACK(72); _NS_RETURN_HACK(73); _NS_RETURN_HACK(74); + _NS_RETURN_HACK(75); _NS_RETURN_HACK(76); _NS_RETURN_HACK(77); + _NS_RETURN_HACK(78); _NS_RETURN_HACK(79); _NS_RETURN_HACK(80); + _NS_RETURN_HACK(81); _NS_RETURN_HACK(82); _NS_RETURN_HACK(83); + _NS_RETURN_HACK(84); _NS_RETURN_HACK(85); _NS_RETURN_HACK(86); + _NS_RETURN_HACK(87); _NS_RETURN_HACK(88); _NS_RETURN_HACK(89); + _NS_RETURN_HACK(90); _NS_RETURN_HACK(91); _NS_RETURN_HACK(92); + _NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95); + _NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98); + _NS_RETURN_HACK(99); + default: val = NULL; break; + } + signal(SIGSEGV, old); + } + else + { + env = jbuf(); + memcpy(&old, env + 1, sizeof(old)); + signal(SIGSEGV, old); + val = NULL; + } + + return val; +} + +static unsigned NSCountFrames(void) +{ + unsigned x = 0; + + while (NSFrameAddress(x + 1)) x++; + + return x; +} + + +static void * +__objc_dynamic_get_symbol_path(dl_handle_t handle, dl_symbol_t symbol) +{ + dl_symbol_t sym; + Dl_info info; + + if (handle == 0) + handle = RTLD_DEFAULT; + + sym = dlsym(handle, symbol); + + if (!sym) + return NULL; + + if (!dladdr(sym, &info)) + return NULL; + + return (void *) info.dli_fname; +} + +static NSArray* +GSListModules() +{ + NSArray *result; + + GSLoadModule(nil); // initialise + [modLock lock]; + result = [stackModules allValues]; + [modLock unlock]; + return result; +} + +@implementation GSStackTrace : NSObject + ++ (GSStackTrace*) currentStack +{ + return [[[GSStackTrace alloc] init] autorelease]; +} + +- (oneway void) dealloc +{ + [frames release]; + frames = nil; + + [super dealloc]; +} + +- (NSString*) description +{ + NSMutableString *result = [NSMutableString string]; + int i; + int n; + + n = [frames count]; + for (i = 0; i < n; i++) + { + id line = [frames objectAtIndex: i]; + + [result appendFormat: @"%3d: %@\n", i, line]; + } + return result; +} + +- (NSEnumerator*) enumerator +{ + return [frames objectEnumerator]; +} + +- (id) frameAt: (unsigned)index +{ + return [frames objectAtIndex: index]; +} + +- (unsigned) frameCount +{ + return [frames count]; +} + +// grab the current stack +- (id) init +{ +#if defined(STACKSYMBOLS) + int i; + int n; + + frames = [[NSMutableArray alloc] init]; + n = NSCountFrames(); + + for (i = 0; i < n; i++) + { + GSFunctionInfo *aFrame = nil; + void *address = NSReturnAddress(i); + void *base; + NSString *modulePath = __objc_dynamic_get_symbol_path(address, &base); + GSBinaryFileInfo *bfi; + + if (modulePath != nil && (bfi = GSLoadModule(modulePath)) != nil) + { + aFrame = [bfi functionForAddress: (void*)(address - base)]; + if (aFrame == nil) + { + /* We know we have the right module be function lookup + * failed ... perhaps we need to use the absolute + * address rather than offest by 'base' in this case. + */ + aFrame = [bfi functionForAddress: address]; + } +//if (aFrame == nil) NSLog(@"BFI base for %@ (%p) is %p", modulePath, address, base); + } + else + { + NSArray *modules; + int j; + int m; + +//if (modulePath != nil) NSLog(@"BFI not found for %@ (%p)", modulePath, address); + + modules = GSListModules(); + m = [modules count]; + for (j = 0; j < m; j++) + { + bfi = [modules objectAtIndex: j]; + + if ((id)bfi != (id)[NSNull null]) + { + aFrame = [bfi functionForAddress: address]; + if (aFrame != nil) + { + break; + } + } + } + } + + // not found (?!), add an 'unknown' function + if (aFrame == nil) + { + aFrame = [GSFunctionInfo alloc]; + [aFrame initWithModule: nil + address: address + file: nil + function: nil + line: 0]; + [aFrame autorelease]; + } + [frames addObject: aFrame]; + } +#else + int i; + int n; + + frames = [[NSMutableArray alloc] init]; + n = NSCountFrames(); + + for (i = 0; i < n; i++) + { + void *address = NSReturnAddress(i); + + [frames addObject: [NSString stringWithFormat: @"%p", address]]; + } +#endif + + return self; +} + +- (NSEnumerator*) reverseEnumerator +{ + return [frames reverseObjectEnumerator]; +} + +@end + +// #endif /* GNUSTEP_BASE_MINOR_VERSION */ +// #endif /* GNUSTEP_BASE_MAJOR_VERSION */ diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 4aac23de..fd3ac531 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -466,27 +466,6 @@ static BOOL showTextAttachmentsInline = NO; [self _addRecipients: addrs toArray: allRecipients]; [_info setObject: to forKey: @"to"]; - /* CC processing if we reply-to-all: add all 'to' and 'cc' */ - if (_replyToAll) - { - to = [NSMutableArray new]; - - [addrs setArray: [_envelope to]]; - [self _purgeRecipients: allRecipients - fromAddresses: addrs]; - [self _addEMailsOfAddresses: addrs toArray: to]; - [self _addRecipients: addrs toArray: allRecipients]; - - [addrs setArray: [_envelope cc]]; - [self _purgeRecipients: allRecipients - fromAddresses: addrs]; - [self _addEMailsOfAddresses: addrs toArray: to]; - - [_info setObject: to forKey: @"cc"]; - - [to release]; - } - /* If "to" is empty, we add at least ourself as a recipient! This is for emails in the "Sent" folder that we reply to... */ if (![to count]) @@ -508,6 +487,27 @@ static BOOL showTextAttachmentsInline = NO; [_info removeObjectForKey: @"cc"]; } + /* CC processing if we reply-to-all: add all 'to' and 'cc' */ + if (_replyToAll) + { + to = [NSMutableArray new]; + + [addrs setArray: [_envelope to]]; + [self _purgeRecipients: allRecipients + fromAddresses: addrs]; + [self _addEMailsOfAddresses: addrs toArray: to]; + [self _addRecipients: addrs toArray: allRecipients]; + + [addrs setArray: [_envelope cc]]; + [self _purgeRecipients: allRecipients + fromAddresses: addrs]; + [self _addEMailsOfAddresses: addrs toArray: to]; + + [_info setObject: to forKey: @"cc"]; + + [to release]; + } + [allRecipients release]; [addrs release]; } diff --git a/SoObjects/SOGo/SOGoUserFolder.m b/SoObjects/SOGo/SOGoUserFolder.m index 688d3f04..68bcfcd4 100644 --- a/SoObjects/SOGo/SOGoUserFolder.m +++ b/SoObjects/SOGo/SOGoUserFolder.m @@ -131,27 +131,27 @@ return filter; } -#warning UIxContactsFoldersView should use these methods\ - instead from now on... - - (NSArray *) _subFoldersFromFolder: (SOGoParentFolder *) parentFolder { NSMutableArray *folders; NSEnumerator *subfolders; SOGoFolder *currentFolder; - NSString *folderName; + NSString *folderName, *folderOwner; NSMutableDictionary *currentDictionary; SoSecurityManager *securityManager; + folderOwner = [parentFolder ownerInContext: context]; securityManager = [SoSecurityManager sharedSecurityManager]; - + folders = [NSMutableArray array]; subfolders = [[parentFolder subFolders] objectEnumerator]; while ((currentFolder = [subfolders nextObject])) { if (![securityManager validatePermission: SOGoPerm_AccessObject - onObject: currentFolder inContext: context]) + onObject: currentFolder inContext: context] + && [[currentFolder ownerInContext: context] + isEqualToString: folderOwner]) { folderName = [NSString stringWithFormat: @"/%@/%@", [parentFolder nameInContainer], diff --git a/UI/Contacts/UIxContactFoldersView.m b/UI/Contacts/UIxContactFoldersView.m index 9605ed56..c662072a 100644 --- a/UI/Contacts/UIxContactFoldersView.m +++ b/UI/Contacts/UIxContactFoldersView.m @@ -221,121 +221,6 @@ return folders; } -- (NSArray *) _foldersForUID: (NSString *) uid - ofType: (NSString *) folderType -{ - NSObject *topFolder, *userFolder; - SOGoParentFolder *parentFolder; - NSMutableArray *folders; - - folders = [NSMutableArray new]; - [folders autorelease]; - - topFolder = [[[self clientObject] container] container]; - userFolder = [topFolder lookupName: uid inContext: context acquire: NO]; - - /* FIXME: should be moved in the SOGo* classes. Maybe by having a SOGoFolderManager. */ - if ([folderType length] == 0 || [folderType isEqualToString: @"calendar"]) - { - parentFolder = [userFolder lookupName: @"Calendar" - inContext: context acquire: NO]; - [folders - addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]]; - } - if ([folderType length] == 0 || [folderType isEqualToString: @"contact"]) - { - parentFolder = [userFolder lookupName: @"Contacts" - inContext: context acquire: NO]; - [folders - addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]]; - } - - return folders; -} - -- (NSString *) _foldersStringForFolders: (NSEnumerator *) folders -{ - NSMutableString *foldersString; - NSDictionary *currentFolder; - - foldersString = [NSMutableString new]; - [foldersString autorelease]; - - currentFolder = [folders nextObject]; - while (currentFolder) - { - [foldersString appendFormat: @";%@:%@:%@", - [currentFolder objectForKey: @"displayName"], - [currentFolder objectForKey: @"name"], - [currentFolder objectForKey: @"type"]]; - currentFolder = [folders nextObject]; - } - - return foldersString; -} - -- (WOResponse *) _foldersResponseForResults: (NSArray *) results - withType: (NSString *) folderType -{ - WOResponse *response; - NSString *uid, *foldersString; - NSMutableString *responseString; - NSDictionary *contact; - NSEnumerator *contacts; - NSArray *folders; - - response = [context response]; - - if ([results count]) - { - [response setStatus: 200]; - [response setHeader: @"text/plain; charset=utf-8" - forKey: @"Content-Type"]; - - responseString = [NSMutableString new]; - contacts = [results objectEnumerator]; - while ((contact = [contacts nextObject])) - { - uid = [contact objectForKey: @"c_uid"]; - folders = [self _foldersForUID: uid ofType: folderType]; - foldersString - = [self _foldersStringForFolders: [folders objectEnumerator]]; - [responseString appendFormat: @"%@:%@:%@%@\n", uid, - [contact objectForKey: @"cn"], - [contact objectForKey: @"c_email"], - foldersString]; - } - [response appendContentString: responseString]; - [responseString release]; - } - else - [response setStatus: 404]; - - return response; -} - -- (id ) foldersSearchAction -{ - NSString *contact, *folderType; - id result; - LDAPUserManager *um; - - um = [LDAPUserManager sharedUserManager]; - contact = [self queryParameterForKey: @"search"]; - if ([contact length] > 0) - { - folderType = [self queryParameterForKey: @"type"]; - result - = [self _foldersResponseForResults: [um fetchContactsMatching: contact] - withType: folderType]; - } - else - result = [NSException exceptionWithHTTPStatus: 400 - reason: @"missing 'search' parameter"]; - - return result; -} - // - (SOGoContactGCSFolder *) contactFolderForUID: (NSString *) uid // { // SOGoFolder *upperContainer; diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 1b4d7eb3..88da1673 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -27,11 +27,6 @@ pageName = "UIxContactFoldersView"; actionName = "contactSearch"; }; - foldersSearch = { - protectedBy = "View"; - pageName = "UIxContactFoldersView"; - actionName = "foldersSearch"; - }; updateAdditionalAddressBooks = { protectedBy = "View"; pageName = "UIxContactFoldersView"; diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index 5b6b6364..bb696b81 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -24,6 +24,7 @@ #import #import #import + #import #import #import diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m index c5f56913..002e93d4 100644 --- a/UI/MainUI/SOGoUserHomePage.m +++ b/UI/MainUI/SOGoUserHomePage.m @@ -27,6 +27,7 @@ #import #import #import +#import #import #import #import @@ -36,6 +37,7 @@ #import #import #import +#import #import #import @@ -230,4 +232,85 @@ static NSString *defaultModule = nil; return response; } +- (NSString *) _foldersStringForFolders: (NSEnumerator *) folders +{ + NSMutableString *foldersString; + NSDictionary *currentFolder; + + foldersString = [NSMutableString new]; + [foldersString autorelease]; + + currentFolder = [folders nextObject]; + while (currentFolder) + { + [foldersString appendFormat: @";%@:%@:%@", + [currentFolder objectForKey: @"displayName"], + [currentFolder objectForKey: @"name"], + [currentFolder objectForKey: @"type"]]; + currentFolder = [folders nextObject]; + } + + return foldersString; +} + +- (WOResponse *) _foldersResponseForResults: (NSDictionary *) results +{ + WOResponse *response; + NSString *uid, *foldersString; + NSMutableString *responseString; + NSDictionary *contact; + NSEnumerator *contacts; + NSArray *folders; + + response = [context response]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=utf-8" + forKey: @"Content-Type"]; + + responseString = [NSMutableString new]; + contacts = [[results allKeys] objectEnumerator]; + while ((contact = [contacts nextObject])) + { + uid = [contact objectForKey: @"c_uid"]; + folders = [results objectForKey: contact]; + foldersString + = [self _foldersStringForFolders: [folders objectEnumerator]]; + [responseString appendFormat: @"%@:%@:%@%@\n", uid, + [contact objectForKey: @"cn"], + [contact objectForKey: @"c_email"], + foldersString]; + } + [response appendContentString: responseString]; + [responseString release]; + + return response; +} + +- (id ) foldersSearchAction +{ + NSString *contact, *folderType; + NSDictionary *folders; + id result; + + contact = [self queryParameterForKey: @"search"]; + if ([contact length]) + { + folderType = [self queryParameterForKey: @"type"]; + if ([folderType length]) + { + folders = [[self clientObject] foldersOfType: folderType + matchingUID: contact]; + result = [self _foldersResponseForResults: folders]; + } + else + result = [NSException exceptionWithHTTPStatus: 400 + reason: @"missing 'type' parameter"]; + } + else + result = [NSException exceptionWithHTTPStatus: 400 + reason: @"missing 'search' parameter"]; + + return result; +} + @end diff --git a/UI/MainUI/product.plist b/UI/MainUI/product.plist index b41123a7..63e2c5f8 100644 --- a/UI/MainUI/product.plist +++ b/UI/MainUI/product.plist @@ -113,6 +113,11 @@ pageName = "SOGoUserHomePage"; actionName = "logoff"; }; + foldersSearch = { + protectedBy = "View"; + pageName = "SOGoUserHomePage"; + actionName = "foldersSearch"; + }; }; }; SOGoGroupsFolder = { diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css index a0a3dcfe..c19f0004 100644 --- a/UI/WebServerResources/MailerUI.css +++ b/UI/WebServerResources/MailerUI.css @@ -663,8 +663,7 @@ DIV#rightDragHandle overflow: visible; } TD.mailer_fieldname - { text-align: left; - width: auto; } + { text-align: left; } TD.mailer_fieldvalue { white-space: normal; } diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 657ea755..894df77c 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -255,9 +255,11 @@ function deleteSelectedMessagesCallback(http) { // row.addClassName("deleted"); // when we'll offer "mark as deleted" if (deleteMessageRequestCount == 0) { - if (nextRow) + if (nextRow) { Mailer.currentMessages[Mailer.currentMailbox] = nextRow.getAttribute("id").substr(4); - openMailbox(data["mailbox"], true); + nextRow.select(); + loadMessage(Mailer.currentMessages[Mailer.currentMailbox]); + } } } } @@ -522,7 +524,10 @@ function messageListCallback(http) { if (row) { row.select(); lastClickedRow = row.rowIndex - $(row).up('table').down('thead').getElementsByTagName('tr').length; - div.scrollTop = row.rowIndex * row.getHeight(); // scroll to selected message + var rowPosition = row.rowIndex * row.getHeight(); + if ($(row).up('div').getHeight() > rowPosition) + rowPosition = 0; + div.scrollTop = rowPosition; // scroll to selected message } else $("messageContent").update(); @@ -715,7 +720,6 @@ function onMessageSelectionChange() { if (rows.length == 1) { var idx = rows[0].substr(4); - if (Mailer.currentMessages[Mailer.currentMailbox] != idx) { Mailer.currentMessages[Mailer.currentMailbox] = idx; loadMessage(idx); diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index da4c678d..e4ebdd0d 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -74,7 +74,8 @@ function _editEventId(id, calendar) { var targetname = "SOGo_edit_" + id; var win = window.open(urlstr, "_blank", "width=490,height=470,resizable=0"); - win.focus(); + if (win) + win.focus(); } function editEvent() { @@ -346,8 +347,8 @@ function eventsListCallback(http) { startDate.setTime(data[i][4] * 1000); row.day = startDate.getDayString(); row.hour = startDate.getHourString(); - Event.observe(row, "click", - onEventClick.bindAsEventListener(row)); + Event.observe(row, "mousedown", onRowClick); + Event.observe(row, "selectstart", listRowMouseDownHandler); Event.observe(row, "dblclick", editDoubleClickedEvent.bindAsEventListener(row)); Event.observe(row, "contextmenu", @@ -391,7 +392,6 @@ function tasksListCallback(http) { var data = http.responseText.evalJSON(true); for (var i = 0; i < data.length; i++) { - //log(i + " = " + data[i][3]); var listItem = document.createElement("li"); list.appendChild(listItem); Event.observe(listItem, "mousedown", listRowMouseDownHandler); @@ -400,6 +400,7 @@ function tasksListCallback(http) { editDoubleClickedEvent.bindAsEventListener(listItem)); listItem.setAttribute("id", data[i][0]); $(listItem).addClassName(data[i][5]); + $(listItem).addClassName(data[i][6]); listItem.calendar = data[i][1]; $(listItem).addClassName("calendarFolder" + data[i][1]); listItem.cname = escape(data[i][0]); @@ -919,21 +920,10 @@ function popupCalendar(node) { function onEventContextMenu(event) { var topNode = $("eventsList"); -// log(topNode); - var menu = $("eventsListMenu"); Event.observe(menu, "hideMenu", onEventContextMenuHide); popupMenu(event, "eventsListMenu", this); - - var topNode = $("eventsList"); - var selectedNodes = topNode.getSelectedRows(); - topNode.menuSelectedRows = selectedNodes; - for (var i = 0; i < selectedNodes.length; i++) - selectedNodes[i].deselect(); - - topNode.menuSelectedEntry = this; - this.select(); } function onEventContextMenuHide(event) { @@ -943,20 +933,20 @@ function onEventContextMenuHide(event) { topNode.menuSelectedEntry.deselect(); topNode.menuSelectedEntry = null; } - if (topNode.menuSelectedRows) { - var nodeIds = topNode.menuSelectedRows; - for (var i = 0; i < nodeIds.length; i++) { - var node = $(nodeIds[i]); - node.select(); - } - topNode.menuSelectedRows = null; - } } function onEventsSelectionChange() { listOfSelection = this; this.removeClassName("_unfocused"); $("tasksList").addClassName("_unfocused"); + + var rows = this.tBodies[0].getSelectedNodes(); + if (rows.length == 1) { + var row = rows[0]; + changeCalendarDisplay( { "day": row.day, + "scrollEvent": row.getAttribute("id") } ); + changeDateSelectorDisplay(row.day); + } } function onTasksSelectionChange() { @@ -1048,14 +1038,6 @@ function onListFilterChange() { return refreshEvents(); } -function onEventClick(event) { - changeCalendarDisplay( { "day": this.day, - "scrollEvent": this.getAttribute("id") } ); - changeDateSelectorDisplay(this.day); - - return onRowClick(event); -} - function selectMonthInMenu(menu, month) { var entries = menu.childNodes[1].childNodesWithTag("LI"); for (i = 0; i < entries.length; i++) { @@ -1721,9 +1703,6 @@ function configureLists() { TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true}); Event.observe(list, "mousedown", onEventsSelectionChange.bindAsEventListener(list)); - var div = list.parentNode; - Event.observe(div, "contextmenu", - onEventContextMenu.bindAsEventListener(div)); } function initDateSelectorEvents() { diff --git a/UI/WebServerResources/UIxContactsUserFolders.js b/UI/WebServerResources/UIxContactsUserFolders.js index 1855cc45..fe55efc3 100644 --- a/UI/WebServerResources/UIxContactsUserFolders.js +++ b/UI/WebServerResources/UIxContactsUserFolders.js @@ -1,8 +1,8 @@ function onSearchFormSubmit() { var searchValue = $("searchValue"); - var url = (ApplicationBaseURL - + "/foldersSearch?ldap-only=YES&search=" + escape(searchValue.value) + var url = (UserFolderURL + + "foldersSearch?search=" + escape(searchValue.value) + "&type=" + window.opener.userFolderType); if (document.userFoldersRequest) { document.userFoldersRequest.aborted = true; @@ -30,7 +30,7 @@ function addLineToTree(tree, parent, line) { for (var i = 1; i < nodes.length; i++) { var folderInfos = nodes[i].split(":"); var icon = ResourcesURL + '/'; - if (folderInfos[2] == 'Contacts') + if (folderInfos[2] == 'Contact') icon += 'tb-mail-addressbook-flat-16x16.png'; else icon += 'calendar-folder-16x16.png'; @@ -97,6 +97,7 @@ function userFoldersCallback(http) { if (http.status == 200) { var response = http.responseText; div.innerHTML = buildTree(http.responseText); + div.clean = false; var nodes = document.getElementsByClassName("node", $("d")); for (i = 0; i < nodes.length; i++) Event.observe(nodes[i], "click", onFolderTreeItemClick.bindAsEventListener(nodes[i])); @@ -136,9 +137,17 @@ function onConfirmFolderSelection(event) { } } +function onFolderSearchKeyDown(event) { + var div = $("folders"); + if (!div.clean) { + div.innerHTML = ""; + div.clean = true; + } +} + function initUserFoldersWindow() { - configureSearchField(); - Event.observe($("addButton"), "click", onConfirmFolderSelection); + $("searchValue").observe("keydown", onFolderSearchKeyDown); + $("addButton").observe("click", onConfirmFolderSelection); } FastInit.addOnLoad(initUserFoldersWindow); diff --git a/UI/WebServerResources/UIxMailToSelection.js b/UI/WebServerResources/UIxMailToSelection.js index 4a30bdf5..e76dfd54 100644 --- a/UI/WebServerResources/UIxMailToSelection.js +++ b/UI/WebServerResources/UIxMailToSelection.js @@ -140,20 +140,20 @@ function addressFieldLostFocus(sender) { } function removeLastEditedRowIfEmpty() { - var idx, addr, addressList, senderRow; + var addr, addressList, senderRow; - idx = lastIndex; - if (idx == 0) return; - addr = $('addr_' + idx); + addressList = $("addressList").tBodies[0]; + + if (lastIndex == 0 && addressList.childNodes.length <= 2) return; + addr = $('addr_' + lastIndex); if (!addr) return; if (addr.value.strip() != '') return; - addr = this.findAddressWithIndex(idx); + addr = this.findAddressWithIndex(lastIndex); if(addr) { var addresses = $('addr_addresses'); addresses.removeChild(addr); } - addressList = $("addressList").tBodies[0]; - senderRow = $("row_" + idx); + senderRow = $("row_" + lastIndex); addressList.removeChild(senderRow); } diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js index ce1bace1..6313cd2e 100644 --- a/UI/WebServerResources/generic.js +++ b/UI/WebServerResources/generic.js @@ -509,9 +509,10 @@ function onRowClick(event) { } var initialSelection = $(node.parentNode).getSelectedNodes(); - - if (initialSelection.length > 0 && !Event.isLeftClick(event)) - // Ignore non primary-click (ie right-click) + if (initialSelection.length > 0 + && initialSelection.indexOf(node) >= 0 + && !Event.isLeftClick(event)) + // Ignore non primary-click (ie right-click) inside current selection return true; if ((event.shiftKey == 1 || event.ctrlKey == 1) @@ -917,7 +918,12 @@ function onSearchKeyDown(event) { if (this.timer) clearTimeout(this.timer); - this.timer = setTimeout("onSearchFormSubmit()", 1000); + if (event.keyCode == 13) { + onSearchFormSubmit(); + event.preventDefault(); + } + else + this.timer = setTimeout("onSearchFormSubmit()", 1000); } function onSearchFormSubmit(event) { -- 2.39.5