1/*
2**  GNUMail.m
3**
4**  Copyright (c) 2001-2007 Ludovic Marcotte
5**  Copyright (C) 2014-2018 Riccardo Mottola
6**
7**  Authors: Ludovic Marcotte <ludovic@Sophos.ca>
8**           Riccardo Mottola <rm@gn.org>
9**
10**  This program is free software; you can redistribute it and/or modify
11**  it under the terms of the GNU General Public License as published by
12**  the Free Software Foundation; either version 2 of the License, or
13**  (at your option) any later version.
14**
15**  This program is distributed in the hope that it will be useful,
16**  but WITHOUT ANY WARRANTY; without even the implied warranty of
17**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18**  GNU General Public License for more details.
19**
20**  You should have received a copy of the GNU General Public License
21**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#import "GNUMail.h"
25
26#import "AboutPanelController.h"
27#import "AddressBookController.h"
28#import "ApplicationIconController.h"
29#import "ConsoleWindowController.h"
30#import "EditWindowController.h"
31#import "ExtendedMenuItem.h"
32#import "ExtendedWindow.h"
33#import "Filter.h"
34#import "FilterManager.h"
35#import "FindWindowController.h"
36#import "FolderNode.h"
37#import "GNUMail+Extensions.h"
38#import "GNUMailBundle.h"
39#import "Constants.h"
40#import "MailWindowController.h"
41#import "MailboxInspectorPanelController.h"
42#import "MailboxManagerCache.h"
43#import "MailboxManagerController.h"
44#import "MessageViewWindowController.h"
45#import "MimeTypeManager.h"
46#import "MimeType.h"
47#import "NSAttributedString+Extensions.h"
48#import "NSBundle+Extensions.h"
49#import "NSPasteboard+Extensions.h"
50#import "NSUserDefaults+Extensions.h"
51#import "PreferencesWindowController.h"
52#import "Task.h"
53#import "TaskManager.h"
54#import "Utilities.h"
55#import "MessageComposition.h"
56#import "STScriptingSupport.h"
57#import "WelcomePanel.h"
58
59#import <Pantomime/CWCharset.h>
60#import <Pantomime/CWConstants.h>
61#import <Pantomime/CWContainer.h>
62#import <Pantomime/CWFlags.h>
63#import <Pantomime/CWInternetAddress.h>
64#import <Pantomime/CWIMAPCacheManager.h>
65#import <Pantomime/CWIMAPFolder.h>
66#import <Pantomime/CWIMAPStore.h>
67#import <Pantomime/CWLocalFolder.h>
68#import <Pantomime/CWLocalStore.h>
69#import <Pantomime/CWInternetAddress.h>
70#import <Pantomime/CWMessage.h>
71#import <Pantomime/CWStore.h>
72#import <Pantomime/CWURLName.h>
73#import <Pantomime/NSFileManager+Extensions.h>
74
75
76// GNUMail's download page -- where to download from
77#define DOWNLOAD_URL	@"http://www.collaboration-world.com/cgi-bin/collaboration-world/project/release.cgi?pid=2"
78
79// GNUMail's Version Property Page
80#define PROPERTY_URL	@"http://www.nongnu.org/gnustep-nonfsf/gnumail/VERSION"
81
82#define TOGGLE_WINDOW(controller) \
83  if ([[[controller singleInstance] window] isVisible]) [[[controller singleInstance] window] orderOut: self]; \
84  else [[controller singleInstance] showWindow: self];
85
86// Static variables
87static NSMutableArray *allEditWindows = nil;
88static NSMutableArray *allEditWindowControllers = nil;
89static NSMutableArray *allMailWindows = nil;
90static NSMutableArray *allMailWindowControllers = nil;
91static NSMutableArray *allBundles;
92
93static NSString *currentWorkingPath = nil;
94
95static id lastAddressTakerWindowOnTop = nil;
96static id lastMailWindowOnTop = nil;
97static id requestLastMailWindowOnTop = nil;
98static BOOL doneInit = NO;
99
100
101//
102// Private methods
103//
104@interface GNUMail (Private)
105- (BOOL) _checkForUpdate;
106- (BOOL) _checkDictionary: (NSDictionary *) theDictionary;
107- (void) _connectToIMAPServers;
108- (void) _loadBundles;
109- (void) _makeFilter: (int) theSource;
110- (void) _newVersionAvailable: (NSString *) theVersion;
111- (void) _removeAllItemsFromMenu: (NSMenu *) theMenu;
112- (void) _savePanelDidEnd: (NSSavePanel *) theSheet
113               returnCode: (int) returnCode
114              contextInfo: (void  *) contextInfo;
115- (void) _updateFilterMenuItems: (id) sender;
116- (void) _updateGetNewMailMenuItems: (id) sender;
117- (void) _updateTextEncodingsMenu: (id) sender;
118- (void) _updateVisibleColumns;
119@end
120
121
122//
123//
124//
125@implementation GNUMail
126
127- (id) init
128{
129  self = [super init];
130
131#ifdef MACOSX
132  _messageCompositions = [[NSMutableArray alloc] init];
133#endif
134  return self;
135}
136
137
138//
139//
140//
141- (void) dealloc
142{
143#ifdef MACOSX
144  RELEASE(dock);
145  RELEASE(_messageCompositions);
146#endif
147
148  [super dealloc];
149}
150
151//
152// action methods
153//
154- (IBAction) addSenderToAddressBook: (id) sender
155{
156  if ([GNUMail lastMailWindowOnTop])
157    {
158      id aController;
159
160      aController = [[GNUMail lastMailWindowOnTop] windowController];
161
162      if ([[aController dataView] numberOfSelectedRows] != 1)
163	{
164	  NSBeep();
165	  return;
166	}
167
168      [[AddressBookController singleInstance] addSenderToAddressBook: [aController selectedMessage]];
169    }
170}
171
172- (IBAction) applyManualFilter: (id) sender
173{
174  if ([GNUMail lastMailWindowOnTop])
175    {
176      MailWindowController *aMailWindowController;
177      FilterManager *aFilterManager;
178      CWFolder *aSourceFolder;
179
180      NSArray *selectedMessages;
181      int i, aTag, aType;
182
183      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
184      selectedMessages = [aMailWindowController selectedMessages];
185
186      if (!selectedMessages || [selectedMessages count] == 0)
187	{
188	  NSBeep();
189	  return;
190	}
191
192      aSourceFolder = [aMailWindowController folder];
193      aTag = [sender tag];
194
195      // If we are in the Sent, we consider ONLY outgoing filters.
196      // Otherwise, we always consider ONLY incoming filters.
197      if ([Utilities stringValueOfURLName: [Utilities stringValueOfURLNameFromFolder: aSourceFolder]
198		      isEqualTo: @"SENTFOLDERNAME"])
199	{
200	  aType = TYPE_OUTGOING;
201	}
202      else
203	{
204	  aType = TYPE_INCOMING;
205	}
206
207      aFilterManager = [FilterManager singleInstance];
208
209      for (i = 0; i < [selectedMessages count]; i++)
210	{
211	  CWMessage *aMessage;
212	  Filter *aFilter;
213
214	  aMessage = [selectedMessages objectAtIndex: i];
215
216	  // If we have selected ALL our filters...
217	  if (aTag < 0)
218	    {
219	      aFilter = [aFilterManager matchedFilterForMessage: aMessage  type: aType];
220	    }
221	  else
222	    {
223	      aFilter = [aFilterManager filterAtIndex: aTag];
224	    }
225
226	  // We verify if the filter matches the message
227	  if (aFilter && [aFilterManager matchExistsForFilter: aFilter  message: aMessage] &&
228	      ([aFilter action] == TRANSFER_TO_FOLDER || [aFilter action] == DELETE))
229	    {
230	      CWFolder *aDestinationFolder;
231	      CWURLName *theURLName;
232
233	      if ([aFilter action] == DELETE)
234		{
235		  NSString *aString;
236
237		  aString = [Utilities accountNameForMessage: aMessage];
238		  theURLName = [[CWURLName alloc] initWithString: [[[[[NSUserDefaults standardUserDefaults] objectForKey: @"ACCOUNTS"] objectForKey: aString]
239								     objectForKey: @"MAILBOXES"] objectForKey: @"TRASHFOLDERNAME"]
240						  path: [[NSUserDefaults standardUserDefaults]
241							  objectForKey: @"LOCALMAILDIR"]];
242		}
243	      else
244		{
245		  theURLName = [[CWURLName alloc] initWithString: [aFilter actionFolderName]
246						  path: [[NSUserDefaults standardUserDefaults]
247							  objectForKey: @"LOCALMAILDIR"]];
248		}
249
250	      AUTORELEASE(theURLName);
251
252	      aDestinationFolder = [[MailboxManagerController singleInstance] folderForURLName: theURLName];
253
254	      if (!aDestinationFolder)
255		{
256		  NSRunAlertPanel(_(@"Error!"),
257				  _(@"An error occurred while trying to open the %@ mailbox. This mailbox was probably\ndeleted and a filter is trying to save mails in it. Check your filters."),
258				  _(@"OK"),
259				  NULL,
260				  NULL,
261				  [theURLName foldername]);
262		  return;
263		}
264
265	      //
266	      // We verify that our target folder isn't the one that is currently open (and last on top)
267	      // If so, we do nothing.
268	      //
269	      if (aDestinationFolder == aSourceFolder)
270		{
271		  return;
272		}
273
274	      [aDestinationFolder setProperty: [NSDate date]  forKey: FolderExpireDate];
275
276	      [[MailboxManagerController singleInstance] transferMessages: [NSArray arrayWithObject: aMessage]
277							 fromStore: [aSourceFolder store]
278							 fromFolder: aSourceFolder
279							 toStore: [aDestinationFolder store]
280							 toFolder: aDestinationFolder
281							 operation: MOVE_MESSAGES];
282	    } // if ( aFilter && [aFilterManager ...] )
283	} // for (...)
284    }
285  else
286    {
287      NSBeep();
288    }
289}
290
291
292#ifdef MACOSX
293//
294//
295//
296- (void) awakeFromNib
297{
298  NSMenuItem *item;
299
300  dock = [[NSMenu alloc] init];
301  [dock setAutoenablesItems: NO];
302
303  item = [[NSMenuItem alloc] initWithTitle: _(@"New Message")
304			     action: @selector(composeMessage:)
305			     keyEquivalent: @""];
306  [dock addItem: item];
307  RELEASE(item);
308}
309
310//
311//
312//
313- (NSMenu *) applicationDockMenu: (NSApplication *) sender
314{
315  return dock;
316}
317
318//
319//
320//
321- (BOOL) applicationShouldHandleReopen: (NSApplication *) theApplication  hasVisibleWindows: (BOOL) theBOOL
322{
323  if (![[GNUMail allMailWindows] count])
324    {
325      [self newViewerWindow: theApplication];
326    }
327
328  return NO;
329}
330#endif
331
332
333//
334//
335//
336- (IBAction) changeTextEncoding: (id) sender
337{
338  NSWindow *aWindow;
339
340  aWindow = [NSApp keyWindow];
341
342  if (!aWindow)
343    {
344      NSBeep();
345      return;
346    }
347  else
348    {
349      id aWindowController;
350
351      aWindowController = [aWindow windowController];
352
353      //
354      // We are working with a MailWindowController / MessageViewWindowController
355      //
356      if ([aWindowController isKindOfClass: [MailWindowController class]] ||
357	  [aWindowController isKindOfClass: [MessageViewWindowController class]])
358	{
359	  CWMessage *theMessage;
360
361	  if ([aWindowController isKindOfClass: [MailWindowController class]])
362	    {
363	      theMessage = [aWindowController selectedMessage];
364	    }
365	  else
366	    {
367	      theMessage = [(MessageViewWindowController *)aWindowController message];
368	    }
369
370	  if (theMessage)
371	    {
372	      NSString *theCharset;
373	      NSData *aData;
374	      id aDataView;
375
376	      aDataView = [aWindowController dataView];
377
378	      if ([sender tag] == -1)
379		{
380		  theCharset = [theMessage charset];
381		}
382	      else
383		{
384		  theCharset = [[[CWCharset allCharsets] allKeysForObject: [sender title]] objectAtIndex: 0];
385		}
386
387	      [theMessage setDefaultCharset: theCharset];
388	      aData = [theMessage rawSource];
389
390	      if (aData)
391		{
392		  NSAutoreleasePool *pool;
393		  CWMessage *aMessage;
394
395		  pool = [[NSAutoreleasePool alloc] init];
396
397		  aMessage = [[CWMessage alloc] initWithData: aData  charset: theCharset];
398
399		  // We show the new message
400		  [Utilities showMessage: aMessage
401			     target: [aWindowController textView]
402			     showAllHeaders: [aWindowController showAllHeaders]];
403
404		  // We set the new headers of the message and we refresh the selected row in our data view
405		  [theMessage setHeaders: [aMessage allHeaders]];
406		  [aDataView setNeedsDisplayInRect: [aDataView rectOfRow: [aDataView selectedRow]]];
407
408		  RELEASE(aMessage);
409		  RELEASE(pool);
410		}
411	      else
412		{
413		  Task *aTask;
414
415		  [theMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageLoading];
416		  [theMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageDestinationChangeEncoding];
417
418		  aTask = [[Task alloc] init];
419		  [aTask setKey: [Utilities accountNameForFolder: [theMessage folder]]];
420		  aTask->op = LOAD_ASYNC;
421		  aTask->immediate = YES;
422 		  aTask->total_size = (float)[theMessage size]/(float)1024;
423		  [aTask setMessage: theMessage];
424		  [aTask addController: aWindowController];
425		  [[TaskManager singleInstance] addTask: aTask];
426		  RELEASE(aTask);
427		}
428	    }
429	  else
430	    {
431	      NSBeep();
432	    }
433	}
434      //
435      // We are working with an EditWindowController
436      //
437      else if ([aWindowController isKindOfClass: [EditWindowController class]])
438	{
439	  [aWindowController setCharset: [sender title]];
440	}
441      //
442      // The rest, just beep!
443      //
444      else
445	{
446	  NSBeep();
447	}
448    }
449}
450
451
452//
453// Handles the 'check for update' request
454//
455- (IBAction) checkForUpdates: (id) sender
456{
457  NSString *msg, *error;
458
459  msg = nil;
460  error = nil;
461
462  NS_DURING
463    {
464      if (![self _checkForUpdate])
465        {
466          msg = [NSString stringWithFormat: _(@"There is no new version of %@ available."),
467			  [[NSProcessInfo processInfo] processName]];
468          error = @"";
469        }
470    }
471  NS_HANDLER
472    {
473      msg = _(@"Unable to check for new software.");
474      error = [NSString stringWithFormat: _(@"Check failed due to the following reason:\n%@"),
475			[localException reason]];
476    }
477  NS_ENDHANDLER {}
478
479  if (msg)
480    {
481      NSRunInformationalAlertPanel(msg, error, _(@"OK"), NULL, NULL);
482    }
483
484  return;
485}
486
487
488//
489//
490//
491- (IBAction) close: (id) sender
492{
493  if ([NSApp keyWindow])
494    {
495      [[NSApp keyWindow] performClose: sender];
496    }
497}
498
499
500//
501//
502//
503- (IBAction) compactMailbox: (id) sender
504{
505  if ([GNUMail lastMailWindowOnTop])
506    {
507      int choice;
508
509      choice = NSAlertDefaultReturn;
510
511      if (![[NSUserDefaults standardUserDefaults] objectForKey: @"PROMPT_BEFORE_COMPACT"] ||
512	  [[NSUserDefaults standardUserDefaults] boolForKey: @"PROMPT_BEFORE_COMPACT"])
513	{
514	  choice = NSRunAlertPanel(_(@"Compact..."),
515				   _(@"Compacting a mailbox will permanently remove deleted messages.\nDo you want to continue?"),
516				   _(@"Compact"),  // default
517				   _(@"Cancel"),   // alternate
518				   NULL);
519	}
520
521      if (choice == NSAlertDefaultReturn)
522	{
523	  CWFolder* aFolder;
524
525	  aFolder = [(MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate] folder];
526
527	  ADD_CONSOLE_MESSAGE(_(@"Compacting mailbox, please wait..."), [aFolder name]);
528	  [aFolder expunge];
529
530	  if ([aFolder isKindOfClass: [CWIMAPFolder class]])
531	    {
532	      Task *aTask;
533
534	      aTask = [[Task alloc] init];
535	      aTask->op = EXPUNGE_ASYNC;
536	      [aTask setKey: [Utilities accountNameForFolder: aFolder]];
537	      aTask->immediate = YES;
538	      [[TaskManager singleInstance] addTask: aTask];
539	      RELEASE(aTask);
540	    }
541	}
542    }
543  else
544    {
545      NSBeep();
546    }
547}
548
549
550//
551// This method is used to compose a new message, with an empty content.
552//
553- (IBAction) composeMessage: (id) sender
554{
555  EditWindowController *editWindowController;
556  CWMessage *aMessage;
557
558  // We create an empty message
559  aMessage = [[CWMessage alloc] init];
560
561  // We create our controller and we show the window
562  editWindowController = [[EditWindowController alloc] initWithWindowNibName: @"EditWindow"];
563
564  [allEditWindowControllers addObject: editWindowController];
565  [editWindowController release];
566
567  if (editWindowController)
568    {
569      id aMailWindowController;
570
571      [[editWindowController window] setTitle: _(@"New message...")];
572      [editWindowController setMessage: aMessage];
573      [editWindowController setShowCc: NO];
574
575      // We try to guess the best account to use
576      aMailWindowController = [GNUMail lastMailWindowOnTop];
577
578      if (aMailWindowController)
579	{
580	  [editWindowController setAccountName: [Utilities accountNameForFolder: [[aMailWindowController windowController] folder]]];
581	}
582      else
583	{
584	  [editWindowController setAccountName: nil];
585	}
586
587      [editWindowController showWindow: self];
588    }
589
590  RELEASE(aMessage);
591}
592
593
594
595//
596//
597//
598- (IBAction) copy: (id) sender
599{
600  NSPasteboard *aPasteboard;
601
602  aPasteboard = [NSPasteboard generalPasteboard];
603
604  if ([[[NSApp keyWindow] delegate] isKindOfClass: [MailWindowController class]] && [GNUMail lastMailWindowOnTop])
605    {
606      MailWindowController *aMailWindowController;
607      NSMutableArray *messagesToLoad;
608      NSArray *allMessages;
609      CWMessage *aMessage;
610      Task *aTask;
611      int count;
612
613      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
614      allMessages = [aMailWindowController selectedMessages];
615      count = [allMessages count];
616      aMessage = nil;
617
618      if (count)
619	{
620	  messagesToLoad = [NSMutableArray array];
621	  aTask = [[Task alloc] init];
622	  aTask->op = LOAD_ASYNC;
623	  aTask->immediate = YES;
624
625	  // First, we clear our existing property list.
626	  [aPasteboard setPropertyList: [NSArray array]  forType: MessagePboardType];
627
628	  while (count--)
629	    {
630	      aMessage = (CWMessage *)[allMessages objectAtIndex: count];
631
632	      if ([aMessage rawSource])
633		{
634		  [aPasteboard addMessage: [allMessages objectAtIndex: count]];
635		}
636	      else
637		{
638		  [aMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageLoading];
639		  [aMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageDestinationPasteboard];
640		  [messagesToLoad addObject: aMessage];
641		  aTask->total_size += (float)[aMessage size]/(float)1024;
642		}
643	    }
644
645
646	  if ([messagesToLoad count])
647	    {
648	      [aTask setKey: [Utilities accountNameForFolder: [aMessage folder]]];
649	      [aTask setMessage: messagesToLoad];
650	      aTask->total_count = [messagesToLoad count];
651	      [[TaskManager singleInstance] addTask: aTask];
652	    }
653
654	  RELEASE(aTask);
655
656	  // If the sender is self, that means we performed a "cut" operation.
657	  // Let's mark the messages as deleted and refresh the associated view.
658	  if (sender == self)
659	    {
660	      CWFlags *theFlags;
661
662	      count = [allMessages count];
663
664	      while (count--)
665		{
666		  aMessage = [allMessages objectAtIndex: count];
667		  theFlags = [[aMessage flags] copy];
668
669		  // We set the flag PantomimeDeleted to the message
670		  [theFlags add: PantomimeDeleted];
671		  [aMessage setFlags: theFlags];
672		  RELEASE(theFlags);
673		}
674
675	      [[aMailWindowController folder] updateCache];
676	      [aMailWindowController tableViewShouldReloadData];
677	      [aMailWindowController updateStatusLabel];
678	    }
679	}
680      else
681	{
682	  NSBeep();
683	}
684    }
685  else
686    {
687      NSBeep();
688    }
689}
690
691
692//
693//
694//
695//
696//
697//
698- (IBAction) customizeToolbar: (id) sender
699{
700  NSWindow *aWindow;
701
702  aWindow = [NSApp keyWindow];
703
704  if (aWindow && [aWindow toolbar])
705    {
706      [[aWindow toolbar] runCustomizationPalette: sender];
707    }
708}
709
710//
711//
712//
713- (IBAction) cut: (id) sender
714{
715  [self copy: self];
716}
717
718
719//
720//
721//
722- (IBAction) enterSelectionInFindPanel: (id) sender
723{
724  if ([GNUMail lastMailWindowOnTop])
725    {
726      MailWindowController *aMailWindowController;
727      NSTextView *aTextView;
728
729      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
730      aTextView = [aMailWindowController textView];
731
732      [[[FindWindowController singleInstance]
733	 findField] setStringValue: [[aTextView string] substringWithRange: [aTextView selectedRange]]];
734    }
735  else
736    {
737      NSBeep();
738    }
739}
740
741
742//
743//
744//
745- (IBAction) findNext: (id) sender
746{
747  [[FindWindowController singleInstance] nextMessage: nil];
748}
749
750
751//
752//
753//
754- (IBAction) findPrevious: (id) sender
755{
756  [[FindWindowController singleInstance] previousMessage: nil];
757}
758
759
760//
761// This method is used to forward the selected messsage from the last
762// mail window that was on top.
763//
764- (IBAction) forwardMessage: (id) sender
765{
766  if ([GNUMail lastMailWindowOnTop])
767    {
768      CWMessage *aMessage;
769      int tag;
770
771      aMessage = [[[GNUMail lastMailWindowOnTop] delegate] selectedMessage];
772
773      if (!aMessage)
774	{
775	  NSBeep();
776	  return;
777	}
778
779      tag = [sender tag];
780
781      if (tag == PantomimeAttachmentForwardMode)
782	{
783	  [Utilities forwardMessage: aMessage  mode: PantomimeAttachmentForwardMode];
784	}
785      else
786	{
787	  [Utilities forwardMessage: aMessage  mode: PantomimeInlineForwardMode];
788	}
789    }
790  else
791    {
792      NSBeep();
793    }
794}
795
796
797//
798// This method is used to get the new messages if the LocalInboxWindow
799// is currently opened and visible.
800//
801- (IBAction) getNewMessages: (id) sender
802{
803  id aController;
804
805  aController = [GNUMail lastMailWindowOnTop];
806
807  if (aController)
808    {
809      aController = [[GNUMail lastMailWindowOnTop] windowController];
810
811      if ([aController isKindOfClass: [MessageViewWindowController class]])
812	{
813	  aController = [(MessageViewWindowController *)aController mailWindowController];
814	}
815    }
816
817  [[TaskManager singleInstance] checkForNewMail: sender  controller: aController];
818}
819
820
821//
822//
823//
824- (IBAction) importMailboxes: (id) sender
825{
826  NSString *aString;
827  NSBundle *aBundle;
828
829#ifdef MACOSX
830  aString = [[[NSBundle mainBundle] builtInPlugInsPath]
831	      stringByAppendingPathComponent: @"Import.bundle"];
832#else
833  NSArray *allPaths;
834  BOOL b;
835  NSUInteger i;
836
837  allPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
838						 NSLocalDomainMask|
839						 NSNetworkDomainMask|
840						 NSSystemDomainMask|
841						 NSUserDomainMask,
842						 YES);
843  aString = nil;
844
845  for (i = 0; i < [allPaths count]; i++)
846    {
847      aString = [NSString stringWithFormat: @"%@/GNUMail/Import.bundle", [allPaths objectAtIndex: i]];
848
849      if ([[NSFileManager defaultManager] fileExistsAtPath: aString  isDirectory: &b] && b)
850	{
851	  break;
852	}
853    }
854#endif
855
856  aBundle = [NSBundle bundleWithPath: aString];
857
858  if (aBundle)
859    {
860      [[[aBundle principalClass] singleInstance] showWindow: self];
861      return;
862    }
863
864  // We were unable to load the Import bundle.
865  NSBeep();
866}
867
868
869//
870//
871//
872- (IBAction) makeFilterFromListId: (id) sender
873{
874  [self _makeFilter: EXPERT];
875}
876
877//
878//
879//
880- (IBAction) makeFilterFromSender: (id) sender
881{
882  [self _makeFilter: FROM];
883}
884
885//
886//
887//
888- (IBAction) makeFilterFromTo: (id) sender
889{
890  [self _makeFilter: TO];
891}
892
893//
894//
895//
896- (IBAction) makeFilterFromCc: (id) sender
897{
898  [self _makeFilter: CC];
899}
900
901
902//
903//
904//
905- (IBAction) makeFilterFromSubject: (id)sender
906{
907  [self _makeFilter: SUBJECT];
908}
909
910
911
912//
913//
914//
915- (IBAction) nextUnreadMessage: (id) sender
916{
917  if ( [GNUMail lastMailWindowOnTop] &&
918       [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]] )
919    {
920      [[[GNUMail lastMailWindowOnTop] delegate] nextUnreadMessage: sender];
921    }
922  else
923    {
924      NSBeep();
925    }
926}
927
928
929//
930//
931//
932- (IBAction) newViewerWindow: (id) sender
933{
934  MailWindowController *aMailWindowController;
935
936  aMailWindowController = [[MailWindowController alloc] initWithWindowNibName: @"MailWindow"];
937  [allMailWindowControllers addObject: aMailWindowController];
938  [aMailWindowController release];
939
940  [aMailWindowController setFolder: nil];
941  [[aMailWindowController window] orderFrontRegardless];
942  [[aMailWindowController window] makeKeyAndOrderFront: nil];
943}
944
945
946//
947//
948//
949- (IBAction) paste: (id) sender
950{
951  NSArray *types, *propertyList;
952  NSPasteboard *pboard;
953  NSString *aType;
954  int i;
955
956  // We verify every supported pasteboard type
957  pboard = [NSPasteboard generalPasteboard];
958  types = [pboard types];
959
960  for (i = 0; i < [types count]; i++)
961    {
962      aType = (NSString*)[types objectAtIndex: i];
963
964      //
965      // MessagePboardType
966      //
967      if ([MessagePboardType isEqualToString: aType])
968	{
969	  propertyList = [pboard propertyListForType: MessagePboardType];
970
971	  if (propertyList)
972	    {
973	      MailWindowController *aMailWindowController;
974	      int count;
975
976	      aMailWindowController = nil;
977
978#ifndef MACOSX
979	      //
980	      // The front window is the Mailboxes window. Let's get the associated
981	      // MailWindow of the selected item (there must be one!).
982	      //
983	      if ([NSApp keyWindow] == [[MailboxManagerController singleInstance] window])
984		{
985		  MailboxManagerController *aMailboxManagerController;
986		  NSString *aFolderName;
987		  id<CWStore> aStore;
988		  id item;
989
990		  int row, level;
991
992		  aMailboxManagerController = [MailboxManagerController singleInstance];
993		  row = [[aMailboxManagerController outlineView] selectedRow];
994
995		  if (row < 0)
996		    {
997		      NSBeep();
998		      return;
999		    }
1000
1001		  item = [[aMailboxManagerController outlineView] itemAtRow: row];
1002		  level = [[aMailboxManagerController outlineView] levelForItem: item];
1003
1004		  //
1005		  // We must verify that:
1006		  //
1007		  // a) we have at least one selected row
1008		  // b) we haven't selected our root, or a store (Local or IMAP)
1009		  //
1010		  if ([[aMailboxManagerController outlineView] numberOfSelectedRows] != 1 || level < 2)
1011		    {
1012		      NSRunInformationalAlertPanel(_(@"Mailbox error!"),
1013						   _(@"You must select a valid mailbox to open!"),
1014						   _(@"OK"),
1015						   NULL,
1016						   NULL,
1017						   NULL);
1018		      return;
1019		    }
1020
1021		  aStore = [aMailboxManagerController storeForFolderNode: item];
1022		  aFolderName = [Utilities pathOfFolderFromFolderNode: (FolderNode *)item
1023					   separator: [aStore folderSeparator]];
1024		  aMailWindowController = [[Utilities windowForFolderName: aFolderName  store: aStore] windowController];
1025		}
1026#endif
1027
1028	      if (([[[NSApp keyWindow] delegate] isKindOfClass: [MailWindowController class]] && [GNUMail lastMailWindowOnTop]) ||
1029		  aMailWindowController)
1030		{
1031		  if (!aMailWindowController)
1032		    {
1033		      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1034		    }
1035
1036		  count = [propertyList count];
1037
1038		  while (count--)
1039		    {
1040		      // We retrieve the message from the property list
1041		      NSDictionary *aDictionary;
1042		      CWFlags *theFlags;
1043		      NSData *aData;
1044
1045		      aDictionary = (NSDictionary*)[propertyList objectAtIndex: count];
1046		      aData = [aDictionary objectForKey: @"Message"];
1047		      theFlags = (CWFlags*)[NSUnarchiver unarchiveObjectWithData: (NSData*)[aDictionary objectForKey: @"Flags"]];
1048
1049		      if (aData && theFlags)
1050			{
1051			  [[MailboxManagerController singleInstance] transferMessage: aData
1052								     flags: theFlags
1053								     folder: [aMailWindowController folder]];
1054			}
1055		    }
1056
1057		  if ([propertyList count] > 0)
1058		    {
1059		      [aMailWindowController tableViewShouldReloadData];
1060		      [aMailWindowController updateStatusLabel];
1061		    }
1062		}
1063	      else
1064		{
1065		  NSBeep();
1066		}
1067	    }
1068	}
1069
1070    }
1071}
1072
1073
1074//
1075//
1076//
1077- (IBAction) previousUnreadMessage: (id) sender
1078{
1079  if ([GNUMail lastMailWindowOnTop] &&
1080      [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]])
1081    {
1082      [[[GNUMail lastMailWindowOnTop] delegate] previousUnreadMessage: sender];
1083    }
1084  else
1085    {
1086      NSBeep();
1087    }
1088}
1089
1090
1091//
1092// This method prints the current selected message - ie., the one
1093// shown in the MailWindow's (or MessageViewWindow) text view.
1094//
1095- (IBAction) printMessage: (id) sender
1096{
1097  if ([GNUMail lastMailWindowOnTop])
1098    {
1099      NSPrintInfo *aPrintInfo;
1100      id aWindowController;
1101
1102      aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
1103      aPrintInfo = [NSPrintInfo sharedPrintInfo];
1104      [aPrintInfo setHorizontalPagination: NSFitPagination];
1105
1106      [[NSPrintOperation printOperationWithView: [aWindowController textView]  printInfo: aPrintInfo] runOperation];
1107    }
1108  else
1109    {
1110      NSBeep();
1111    }
1112}
1113
1114// this method is needed due to changes in Framework/GNUMail/MessageViewWindowToolbar.m
1115// now using NSToolbarPrintItemIdentifier instead of the custom print method
1116// needs to be changed when the MainMenu NIB can be updated to use printDocument
1117// instead of printMessage, then the printMessage can just be renamed.
1118- (void) printDocument: (id)sender
1119{
1120  [self printMessage: sender];
1121}
1122
1123
1124//
1125//
1126//
1127- (IBAction) redirectMessage: (id) sender
1128{
1129  if ([GNUMail lastMailWindowOnTop])
1130    {
1131      id aWindowController;
1132      CWMessage *theMessage;
1133
1134      aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
1135      theMessage = [aWindowController selectedMessage];
1136
1137      if (theMessage)
1138	{
1139	  EditWindowController *aController;
1140
1141	  aController = [[EditWindowController alloc] initWithWindowNibName: @"EditWindow"];
1142
1143	  [theMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageRedirecting];
1144	  [aController setMode: GNUMailRedirectMessage];
1145	  [aController setMessage: theMessage];
1146	  [aController setShowCc: NO];
1147	  [aController setAccountName: nil];
1148	  [aController showWindow: self];
1149	}
1150      else
1151	{
1152	  NSBeep();
1153	}
1154    }
1155  else
1156    {
1157      NSBeep();
1158    }
1159}
1160
1161
1162//
1163// This method is used to reply to the selected message.
1164//
1165- (IBAction) replyToMessage: (id) sender
1166{
1167  if ([GNUMail lastMailWindowOnTop])
1168    {
1169      [[[GNUMail lastMailWindowOnTop] delegate] replyToMessage: sender];
1170    }
1171  else
1172    {
1173      NSBeep();
1174    }
1175}
1176
1177
1178//
1179//
1180//
1181- (IBAction) restoreDraft: (id) sender
1182{
1183  CWMessage *aMessage;
1184
1185  aMessage = [[MailboxManagerController singleInstance] messageFromDraftsFolder];
1186
1187  // We create our controller and we show the window if we have a valid message
1188  if (aMessage)
1189    {
1190      EditWindowController *aController;
1191
1192      // Initialize the the message if it has not been already
1193      if (![aMessage isInitialized])
1194	{
1195	  [aMessage setInitialized: YES];
1196	  [aMessage setProperty: [NSNumber numberWithBool: YES]  forKey: @"RestoringFromDrafts"];
1197	}
1198
1199      aController = [[EditWindowController alloc] initWithWindowNibName: @"EditWindow"];
1200      [aController setMode: GNUMailRestoreFromDrafts];
1201      [aController setMessageFromDraftsFolder: aMessage];
1202      [aController updateWithMessage: aMessage];
1203      [aController showWindow: self];
1204    }
1205  else
1206    {
1207      NSBeep();
1208    }
1209}
1210
1211
1212//
1213//
1214//
1215- (IBAction) saveInDrafts: (id) sender
1216{
1217  if ([GNUMail lastAddressTakerWindowOnTop])
1218    {
1219      [[MailboxManagerController singleInstance] saveMessageInDraftsFolderForController: [GNUMail lastAddressTakerWindowOnTop]];
1220    }
1221  else
1222    {
1223      NSBeep();
1224    }
1225}
1226
1227
1228//
1229//
1230//
1231- (IBAction) saveAttachment: (id) sender
1232{
1233  if ([GNUMail lastMailWindowOnTop])
1234    {
1235      NSTextAttachment *aTextAttachment;
1236
1237      aTextAttachment = [sender textAttachment];
1238
1239      [Utilities clickedOnCell: [aTextAttachment attachmentCell]
1240		 inRect: NSZeroRect
1241		 atIndex: 0
1242		 sender: self];
1243    }
1244  else
1245    {
1246      NSBeep();
1247    }
1248}
1249
1250
1251//
1252//
1253//
1254- (IBAction) saveAllAttachments: (id) sender
1255{
1256  NSTextAttachment *aTextAttachment;
1257  NSFileWrapper *aFilewrapper;
1258  NSSavePanel *aSavePanel;
1259
1260  BOOL useSameDir, ask;
1261  int i;
1262
1263  aSavePanel = [NSSavePanel savePanel];
1264  [aSavePanel setAccessoryView: nil];
1265  [aSavePanel setRequiredFileType: @""];
1266
1267  useSameDir = NO;
1268  ask = YES;
1269
1270  for (i = 2; i < [save numberOfItems]; i++ )
1271    {
1272      aTextAttachment = [(ExtendedMenuItem *)[save itemAtIndex: i] textAttachment];
1273      aFilewrapper = [aTextAttachment fileWrapper];
1274
1275      if (!useSameDir)
1276        {
1277          int aChoice;
1278
1279          aChoice = [aSavePanel runModalForDirectory: [GNUMail currentWorkingPath]
1280                                file: [aFilewrapper preferredFilename]];
1281
1282          // if successful, save file under designated name
1283          if ( aChoice == NSOKButton )
1284            {
1285              if (![aFilewrapper writeToFile: [aSavePanel filename]
1286				 atomically: YES
1287				 updateFilenames: YES])
1288                {
1289                  NSBeep();
1290                }
1291	      else
1292		{
1293		  [[NSFileManager defaultManager] enforceMode: 0600  atPath: [aSavePanel filename]];
1294		}
1295
1296              [GNUMail setCurrentWorkingPath: [[aSavePanel filename] stringByDeletingLastPathComponent]];
1297            }
1298        }
1299      else
1300        {
1301          // We save the file in the same directory
1302          if (![aFilewrapper writeToFile: [[GNUMail currentWorkingPath] stringByAppendingPathComponent:
1303									  [aFilewrapper preferredFilename]]
1304			     atomically: YES
1305			     updateFilenames: YES])
1306            {
1307              NSBeep();
1308            }
1309	  else
1310	    {
1311	      [[NSFileManager defaultManager] enforceMode: 0600  atPath: [[GNUMail currentWorkingPath] stringByAppendingPathComponent:
1312													 [aFilewrapper preferredFilename]]];
1313	    }
1314        }
1315
1316      if ( ask )
1317        {
1318          int use = NSRunAlertPanel(_(@"Information"),
1319                                    _(@"Use the same directory (%@) to save all other attachments? (override the files with the same name)."),
1320                                    _(@"Yes"),
1321                                    _(@"No"),
1322                                    NULL,
1323                                    [GNUMail currentWorkingPath]);
1324
1325	  if ( use == NSAlertDefaultReturn )
1326            {
1327              useSameDir = YES;
1328            }
1329          else if ( use == NSAlertAlternateReturn )
1330            {
1331              useSameDir = NO;
1332            }
1333
1334          ask = NO;
1335        }
1336    }
1337}
1338
1339
1340
1341//
1342// This method is used to save only the textual content of a message
1343// to the local file system. It skips attachments.
1344//
1345- (IBAction) saveTextFromMessage: (id) sender
1346{
1347  if ([GNUMail lastMailWindowOnTop])
1348    {
1349      NSSavePanel *aSavePanel;
1350      id aWindowController;
1351      CWMessage *aMessage;
1352      NSWindow *aWindow;
1353
1354      // We get a reference to our mail window controller
1355      aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
1356      aMessage = [aWindowController selectedMessage];
1357
1358      if (aMessage)
1359	{
1360	  NSMutableAttributedString *aMutableAttributedString;
1361	  NSMutableString *aMutableString;
1362	  NSData *aData;
1363	  unichar c;
1364
1365	  //
1366	  // We don't use [[aWindowController textView] string] directly since the string might
1367	  // have been modified by bundles (ie., the Emoticon bundle).
1368	  //
1369	  aMutableAttributedString = [[NSMutableAttributedString alloc]
1370				       initWithAttributedString: [NSAttributedString attributedStringFromContentForPart: aMessage
1371										     controller: aWindowController]];
1372	  [aMutableAttributedString quote];
1373	  [aMutableAttributedString format];
1374
1375	  aMutableString = [NSMutableString stringWithString: [aMutableAttributedString string]];
1376	  RELEASE(aMutableAttributedString);
1377	  c = NSAttachmentCharacter;
1378
1379	  // We replace all attachments with an asterisk
1380	  [aMutableString replaceOccurrencesOfString: [NSString stringWithCharacters: &c  length: 1]
1381			  withString: @"*"
1382			  options: 0
1383			  range: NSMakeRange(0, [aMutableString length])];
1384
1385	  // We get our content of a message (just the text displayed in mail window)
1386	  aData = [aMutableString dataUsingEncoding: NSUTF8StringEncoding
1387				  allowLossyConversion: YES];
1388
1389	  aSavePanel = [NSSavePanel savePanel];
1390	  [aSavePanel setAccessoryView: nil];
1391	  [aSavePanel setRequiredFileType: @""];
1392
1393	  RETAIN(aData);
1394	  if ([sender respondsToSelector:@selector(window)])
1395	    {
1396	      aWindow = [sender window];
1397	    }
1398	  else
1399	    {
1400	      aWindow = [GNUMail lastMailWindowOnTop];
1401	    }
1402	  [aSavePanel beginSheetForDirectory: [GNUMail currentWorkingPath]
1403		      file: [[aWindowController selectedMessage] subject]
1404		      modalForWindow: aWindow
1405		      modalDelegate: self
1406		      didEndSelector: @selector(_savePanelDidEnd: returnCode: contextInfo:)
1407		      contextInfo: aData];
1408	}
1409      else
1410	{
1411	  NSBeep();
1412	}
1413    }
1414  else
1415    {
1416      NSBeep();
1417    }
1418}
1419
1420
1421//
1422//
1423//
1424- (IBAction) selectAllMessagesInThread: (id) sender
1425{
1426  MailWindowController *aController;
1427  CWMessage *aMessage;
1428
1429  aController = [[GNUMail lastMailWindowOnTop] windowController];
1430  aMessage = [aController selectedMessage];
1431
1432  if (aMessage)
1433    {
1434      NSEnumerator *theEnumerator;
1435      CWContainer *aContainer;
1436      int index;
1437
1438      //
1439      // Find the root container
1440      //
1441      aContainer = [aMessage propertyForKey: @"Container"];
1442
1443      // We check if we found a container
1444      if (!aContainer)
1445	{
1446	  return;
1447	}
1448
1449      while (aContainer->parent) aContainer = aContainer->parent;
1450
1451      // We check for the associated message
1452      if (!aContainer->message)
1453	{
1454	  return;
1455	}
1456
1457      //
1458      // We now get all children of the root container. We need them
1459      // in order to select all messages
1460      //
1461      index = [[aController allMessages] indexOfObject: aContainer->message];
1462
1463      if (index >= 0)
1464	{
1465	  [[aController dataView] selectRow: index  byExtendingSelection: NO];
1466	}
1467
1468      theEnumerator = [aContainer childrenEnumerator];
1469
1470      while ((aContainer = [theEnumerator nextObject]))
1471	{
1472	  index = [[aController allMessages] indexOfObject: aContainer->message];
1473
1474	  if (index >= 0)
1475	    {
1476	      [[aController dataView] selectRow: index  byExtendingSelection: YES];
1477	    }
1478	}
1479    }
1480  else
1481    {
1482      NSBeep();
1483    }
1484}
1485
1486
1487//
1488//
1489//
1490- (IBAction) showAboutPanel: (id) sender
1491{
1492  TOGGLE_WINDOW(AboutPanelController);
1493}
1494
1495
1496//
1497//
1498//
1499- (IBAction) sortByNumber: (id) sender
1500{
1501  if ([GNUMail lastMailWindowOnTop] &&
1502      [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]])
1503    {
1504      MailWindowController *aMailWindowController;
1505
1506      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1507
1508      [aMailWindowController
1509	tableView: [aMailWindowController dataView]
1510	didClickTableColumn: [[aMailWindowController dataView]
1511			       tableColumnWithIdentifier: @"#"]];
1512    }
1513  else
1514    {
1515      NSBeep();
1516    }
1517}
1518
1519
1520//
1521//
1522//
1523- (IBAction) sortByDate: (id) sender
1524{
1525  if ( [GNUMail lastMailWindowOnTop] &&
1526       [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]] )
1527    {
1528      MailWindowController *aMailWindowController;
1529
1530      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1531
1532      [aMailWindowController
1533	tableView: [aMailWindowController dataView]
1534	didClickTableColumn: [[aMailWindowController dataView]
1535			       tableColumnWithIdentifier: @"Date"]];
1536    }
1537  else
1538    {
1539      NSBeep();
1540    }
1541}
1542
1543
1544//
1545//
1546//
1547- (IBAction) sortByName: (id) sender
1548{
1549  if ( [GNUMail lastMailWindowOnTop] &&
1550       [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]] )
1551    {
1552      MailWindowController *aMailWindowController;
1553
1554      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1555
1556      [aMailWindowController
1557	tableView: [aMailWindowController dataView]
1558	didClickTableColumn: [[aMailWindowController dataView]
1559			       tableColumnWithIdentifier: @"From"]];
1560    }
1561  else
1562    {
1563      NSBeep();
1564    }
1565}
1566
1567
1568//
1569//
1570//
1571- (IBAction) sortBySubject: (id) sender
1572{
1573  if ( [GNUMail lastMailWindowOnTop] &&
1574       [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]] )
1575    {
1576      MailWindowController *aMailWindowController;
1577
1578      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1579
1580      [aMailWindowController
1581	tableView: [aMailWindowController dataView]
1582	didClickTableColumn: [[aMailWindowController dataView]
1583			       tableColumnWithIdentifier: @"Subject"]];
1584    }
1585  else
1586    {
1587      NSBeep();
1588    }
1589}
1590
1591
1592//
1593//
1594//
1595- (IBAction) sortBySize: (id) sender
1596{
1597  if ( [GNUMail lastMailWindowOnTop] &&
1598       [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]] )
1599    {
1600      MailWindowController *aMailWindowController;
1601
1602      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1603
1604      [aMailWindowController
1605	tableView: [aMailWindowController dataView]
1606	didClickTableColumn: [[aMailWindowController dataView]
1607			       tableColumnWithIdentifier: @"Size"]];
1608    }
1609  else
1610    {
1611      NSBeep();
1612    }
1613}
1614
1615
1616
1617//
1618// This method is used to show the address book on the screen.
1619// We use a singleton.
1620//
1621- (IBAction) showAddressBook: (id) sender
1622{
1623  TOGGLE_WINDOW(AddressBookController);
1624}
1625
1626
1627//
1628// This method is used to view or hide all headers in the
1629// last mail window on top.
1630//
1631- (IBAction) showAllHeaders: (id) sender
1632{
1633  if ([GNUMail lastMailWindowOnTop])
1634    {
1635      id aWindowController;
1636      CWMessage *aMessage;
1637
1638      BOOL aBOOL;
1639      NSInteger row;
1640
1641      aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
1642
1643      if ([aWindowController isKindOfClass: [MailWindowController class]] &&
1644	  (row = [[aWindowController dataView] selectedRow]) &&
1645	  ([[aWindowController dataView] numberOfSelectedRows] > 1))
1646	{
1647	  NSBeep();
1648	  return;
1649	}
1650
1651      if ([sender tag] == SHOW_ALL_HEADERS)
1652	{
1653	  aBOOL = YES;
1654	  [aWindowController setShowAllHeaders: aBOOL];
1655
1656          if ([sender isKindOfClass: [NSButton class]] ||
1657	      [sender isKindOfClass: [NSMenuItem class]])
1658            {
1659	      [sender setTitle: _(@"Filtered Headers")];
1660            }
1661          else
1662            {
1663              [sender setLabel: _(@"Filtered Headers")];
1664            }
1665
1666	  [sender setTag: HIDE_ALL_HEADERS];
1667	}
1668      else
1669	{
1670	  aBOOL = NO;
1671	  [aWindowController setShowAllHeaders: aBOOL];
1672
1673          if ([sender isKindOfClass: [NSButton class]] ||
1674	      [sender isKindOfClass: [NSMenuItem class]])
1675            {
1676	      [sender setTitle: _(@"All Headers")];
1677            }
1678          else
1679            {
1680              [sender setLabel: _(@"All Headers")];
1681            }
1682
1683	  [sender setTag: SHOW_ALL_HEADERS];
1684	}
1685
1686      [menu sizeToFit];
1687
1688      if ([aWindowController isKindOfClass: [MailWindowController class]])
1689	{
1690	  aMessage = [aWindowController selectedMessage];
1691	}
1692      else
1693	{
1694	  aMessage = [(MessageViewWindowController *)aWindowController message];
1695	}
1696
1697      [Utilities showMessage: aMessage
1698		 target: [aWindowController textView]
1699		 showAllHeaders: aBOOL];
1700
1701      //
1702      // Whenever we click on this menu item, we reset the "Raw Source" / "Normal Display"
1703      // menu item to "Raw Source" since it doesn't really make senses to view filtered
1704      // headers on the raw source of a message!
1705      //
1706      [aWindowController setShowRawSource: NO];
1707    }
1708  else
1709    {
1710      NSBeep();
1711    }
1712}
1713
1714
1715//
1716//
1717//
1718- (IBAction) showConsoleWindow: (id) sender
1719{
1720  TOGGLE_WINDOW(ConsoleWindowController);
1721}
1722
1723
1724//
1725// This method is used to show the find window on the screen.
1726// We use a singleton.
1727//
1728- (IBAction) showFindWindow: (id) sender
1729{
1730  TOGGLE_WINDOW(FindWindowController);
1731}
1732
1733
1734//
1735//
1736//
1737- (IBAction) showMailboxInspectorPanel: (id) sender
1738{
1739  TOGGLE_WINDOW(MailboxInspectorPanelController);
1740}
1741
1742
1743//
1744// This method is used to show the mailbox manager window on the screen.
1745// We use a singleton.
1746//
1747- (IBAction) showMailboxManager: (id) sender
1748{
1749  if ([[NSUserDefaults standardUserDefaults] integerForKey: @"PreferredViewStyle"  default: GNUMailDrawerView] == GNUMailDrawerView)
1750    {
1751      if ([GNUMail lastMailWindowOnTop] &&
1752	  [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]])
1753	{
1754	  [[[GNUMail lastMailWindowOnTop] delegate] openOrCloseDrawer: self];
1755	}
1756    }
1757  else
1758    {
1759      TOGGLE_WINDOW(MailboxManagerController);
1760    }
1761}
1762
1763
1764//
1765//
1766//
1767- (IBAction) showOrHideDeletedMessages: (id) sender
1768{
1769  if ([GNUMail lastMailWindowOnTop])
1770    {
1771      MailWindowController *aMailWindowController;
1772
1773      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1774
1775      if ([[aMailWindowController folder] showDeleted])
1776	{
1777	  [[aMailWindowController folder] setShowDeleted: NO];
1778	}
1779      else
1780	{
1781	  [[aMailWindowController folder] setShowDeleted: YES];
1782	}
1783
1784      [aMailWindowController tableViewShouldReloadData];
1785      [aMailWindowController updateStatusLabel];
1786    }
1787  else
1788    {
1789      NSBeep();
1790    }
1791}
1792
1793
1794//
1795//
1796//
1797- (IBAction) showOrHideReadMessages: (id) sender
1798{
1799  if ([GNUMail lastMailWindowOnTop])
1800    {
1801      MailWindowController *aMailWindowController;
1802
1803      aMailWindowController = (MailWindowController *)[[GNUMail lastMailWindowOnTop] delegate];
1804
1805      if ([[aMailWindowController folder] showRead])
1806	{
1807	  [[aMailWindowController folder] setShowRead: NO];
1808	}
1809      else
1810	{
1811	  [[aMailWindowController folder] setShowRead: YES];
1812	}
1813
1814      [aMailWindowController tableViewShouldReloadData];
1815      [aMailWindowController updateStatusLabel];
1816    }
1817  else
1818    {
1819      NSBeep();
1820    }
1821}
1822
1823//
1824//
1825//
1826- (IBAction) showOrHideTableColumns: (id) sender
1827{
1828  NSMutableArray *theColumns;
1829  NSMenuItem *theItem;
1830  int i, count;
1831
1832  theColumns = [[NSMutableArray alloc] init];
1833
1834  if ([sender state] == NSOnState)
1835    {
1836      [sender setState: NSOffState];
1837    }
1838  else
1839    {
1840      [sender setState: NSOnState];
1841    }
1842
1843  count = [columns numberOfItems];
1844
1845  for (i = 0; i < count; i++)
1846    {
1847      theItem = (NSMenuItem *)[columns itemAtIndex: i];
1848
1849      if ([theItem state] == NSOffState)
1850	{
1851	  continue;
1852	}
1853
1854      switch ([theItem tag])
1855	{
1856	case GNUMailDateColumn:
1857	  [theColumns addObject: @"Date"];
1858	  break;
1859
1860	case GNUMailFlagsColumn:
1861	  [theColumns addObject: @"Flagged"];
1862	  break;
1863
1864	case GNUMailFromColumn:
1865	  [theColumns addObject: @"From"];
1866	  break;
1867
1868	case GNUMailNumberColumn:
1869	  [theColumns addObject: @"Number"];
1870	  break;
1871
1872	case GNUMailSizeColumn:
1873	  [theColumns addObject: @"Size"];
1874	  break;
1875
1876	case GNUMailStatusColumn:
1877	  [theColumns addObject: @"Status"];
1878	  break;
1879
1880	case GNUMailSubjectColumn:
1881	  [theColumns addObject: @"Subject"];
1882	  break;
1883	}
1884    }
1885
1886  [[NSUserDefaults standardUserDefaults] setObject: theColumns
1887					 forKey: @"SHOWNTABLECOLUMNS"];
1888  RELEASE(theColumns);
1889
1890  [[NSNotificationCenter defaultCenter]
1891    postNotificationName: TableColumnsHaveChanged
1892    object: nil
1893    userInfo: nil];
1894}
1895
1896//
1897//
1898//
1899- (IBAction) showOrHideToolbar: (id) sender
1900{
1901  NSWindow *aWindow;
1902
1903  aWindow = [NSApp keyWindow];
1904
1905  if (aWindow && [aWindow toolbar])
1906    {
1907      [[aWindow toolbar] setVisible: ([[aWindow toolbar] isVisible] ? NO : YES)];
1908    }
1909}
1910
1911//
1912// This method is used to show the preferences window on the screen.
1913// The window is modal.
1914//
1915- (IBAction) showPreferencesWindow: (id) sender
1916{
1917  [[PreferencesWindowController singleInstance] showWindow: self];
1918}
1919
1920
1921//
1922// This method is used to show the raw source of the selected message
1923// from the last mail window on top.
1924//
1925- (IBAction) showRawSource: (id) sender
1926{
1927  if ([GNUMail lastMailWindowOnTop])
1928    {
1929      id aWindowController;
1930      CWMessage *aMessage;
1931
1932      aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
1933
1934      if (!aWindowController)
1935	{
1936	  NSBeep();
1937	  return;
1938	}
1939
1940      if ([aWindowController isKindOfClass: [MailWindowController class]])
1941	{
1942	  aMessage = [aWindowController selectedMessage];
1943	}
1944      else
1945	{
1946	  aMessage = [(MessageViewWindowController *)aWindowController message];
1947	}
1948
1949      if (aMessage)
1950	{
1951	  if (![aWindowController showRawSource] )
1952	    {
1953	      [aWindowController setShowRawSource: YES];
1954	      if ([sender isKindOfClass: [NSButton class]] ||
1955		  [sender isKindOfClass: [NSMenuItem class]] )
1956		{
1957		  [sender setTitle: _(@"Normal Display")];
1958		}
1959	      else
1960		{
1961		  [sender setLabel: _(@"Normal Display")];
1962		}
1963
1964	      [aMessage setProperty: [NSNumber numberWithBool: YES]  forKey: MessageViewing];
1965	      [Utilities showMessageRawSource: aMessage  target: [aWindowController textView]];
1966	    }
1967	  else
1968	    {
1969	      [aWindowController setShowRawSource: NO];
1970
1971	      if ([sender isKindOfClass: [NSButton class]] ||
1972		  [sender isKindOfClass: [NSMenuItem class]])
1973		{
1974		  [sender setTitle: _(@"Raw Source")];
1975		}
1976	      else
1977		{
1978		  [sender setLabel: _(@"Raw Source")];
1979		}
1980
1981	      [Utilities showMessage: aMessage
1982			 target: [aWindowController textView]
1983			 showAllHeaders: [aWindowController showAllHeaders]];
1984	    }
1985	}
1986      else
1987	{
1988	  NSBeep();
1989	}
1990    }
1991  else
1992    {
1993      NSBeep();
1994    }
1995}
1996
1997
1998//
1999//
2000//
2001- (IBAction) threadOrUnthreadMessages: (id) sender
2002{
2003  if ([GNUMail lastMailWindowOnTop] &&
2004      [[[GNUMail lastMailWindowOnTop] delegate] isKindOfClass: [MailWindowController class]])
2005    {
2006      MailWindowController *aMailWindowController;
2007
2008      aMailWindowController = [[GNUMail lastMailWindowOnTop] delegate];
2009
2010      if ([[aMailWindowController folder] allContainers])
2011	{
2012	  [[aMailWindowController folder] unthread];
2013	}
2014      else
2015	{
2016	  [[aMailWindowController folder] thread];
2017	}
2018
2019      [aMailWindowController tableViewShouldReloadData];
2020      [[NSNotificationCenter defaultCenter] postNotificationName: MessageThreadingNotification
2021					    object: [aMailWindowController folder]];
2022    }
2023  else
2024    {
2025      NSBeep();
2026    }
2027}
2028
2029
2030//
2031// delegate methods
2032//
2033- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) theSender
2034{
2035  NSMutableArray *foldersToOpen;
2036  NSEnumerator *theEnumerator;
2037  id aStore, aWindow;
2038
2039  int choice, i;
2040
2041  if ([[[TaskManager singleInstance] allTasks] count] > 0)
2042    {
2043      choice = NSRunAlertPanel(_(@"Error!"),
2044			       _(@"Not all tasks finished their execution. You must wait before quitting the application.\nOpen the Console (Windows -> Console) if you want to manage those tasks."),
2045			       _(@"OK"),          // default
2046			       _(@"Quit Anyway"), // alternate
2047			       NULL);
2048
2049      if (choice == NSAlertDefaultReturn)
2050	{
2051	  return NSTerminateCancel;
2052	}
2053    }
2054
2055
2056  // If the user has left any "edited" EditWindow:s open, we warn him/her about this
2057  if ([allEditWindows count] > 0)
2058    {
2059      for (i = 0; i < [allEditWindows count]; i++)
2060	{
2061	  if ([[allEditWindows objectAtIndex: i] isDocumentEdited])
2062	    {
2063	      choice = NSRunAlertPanel(_(@"Quit"),
2064				       _(@"There are unsent Compose window."),
2065				       _(@"Review Unsent"), // default
2066				       _(@"Quit Anyway"),   // alternate
2067				       _(@"Cancel"),        // other return
2068				       NULL);
2069
2070	      // We want to review unsent Compose windows
2071	      if (choice == NSAlertDefaultReturn)
2072		{
2073		  [[allEditWindows objectAtIndex: i] makeKeyAndOrderFront: self];
2074		  return NSTerminateCancel;
2075		}
2076	      // We want to quit
2077	      else if (choice == NSAlertAlternateReturn)
2078		{
2079		  break;
2080		}
2081	      // We want to cancel the quit operation
2082	      else
2083		{
2084		  return NSTerminateCancel;
2085		}
2086	    }
2087	}
2088    }
2089
2090  // We first remove all observers
2091  [[NSNotificationCenter defaultCenter] removeObserver: self];
2092
2093  // We release our array containing all our EditWindow:s
2094  DESTROY(allEditWindows);
2095  // and its controllers
2096  DESTROY(allEditWindowControllers);
2097
2098  // We closes all open MailWindow:s. Before doing so, we
2099  // save them in the FOLDERS_TO_OPEN default variable in order
2100  // to reopen them upon the application's startup.
2101  foldersToOpen = [[NSMutableArray alloc] init];
2102
2103  for (i = ([allMailWindows count]-1); i >= 0; i--)
2104    {
2105      aWindow = [allMailWindows objectAtIndex: i];
2106
2107      if (![[aWindow delegate] folder])
2108	{
2109	  [aWindow close];
2110	  continue;
2111	}
2112
2113      if ([[[aWindow delegate] folder] isKindOfClass: [CWLocalFolder class]])
2114	{
2115	  [foldersToOpen addObject: [NSString stringWithFormat: @"local://%@/%@",
2116					      [[NSUserDefaults standardUserDefaults] objectForKey: @"LOCALMAILDIR"],
2117					      [[[aWindow delegate] folder] name]]];
2118	}
2119      else if ([[[aWindow delegate] folder] isKindOfClass: [CWIMAPFolder class]])
2120	{
2121	  [foldersToOpen addObject: [NSString stringWithFormat: @"imap://%@@%@/%@",
2122					      [(CWIMAPStore *)[[[aWindow delegate] folder] store] username],
2123					      [(CWIMAPStore *)[[[aWindow delegate] folder] store] name],
2124					      [[[aWindow delegate] folder] name]]];
2125
2126	}
2127
2128      [aWindow close];
2129    }
2130
2131
2132  // We save our FOLDERS_TO_OPEN value in the user's defaults
2133  [[NSUserDefaults standardUserDefaults] setObject: foldersToOpen
2134					 forKey: @"FOLDERS_TO_OPEN"];
2135  [[NSUserDefaults standardUserDefaults] synchronize];
2136
2137
2138  // We wait until all our windows are closed
2139  while ([allMailWindows count] > 0)
2140    {
2141      [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
2142				  beforeDate: [NSDate distantFuture]];
2143    }
2144
2145  // We release our array containing all our MailWindow:s
2146  DESTROY(allMailWindows);
2147  // and the corresponding controllers
2148  DESTROY(allMailWindowControllers);
2149
2150  // We close all remaining open Store:s
2151  theEnumerator = [[[MailboxManagerController singleInstance] allStores] objectEnumerator];
2152
2153  while ((aStore = [theEnumerator nextObject]))
2154    {
2155      NS_DURING
2156	[aStore close];
2157      NS_HANDLER
2158	// Do nothing
2159      NS_ENDHANDLER
2160    }
2161
2162  // We synchronize our MailboxManagerCache and we close all Stores
2163  [[(MailboxManagerController *)[MailboxManagerController singleInstance] cache] synchronize];
2164
2165  // Under GNUstep, we also close the window before releasing the singleton
2166  if ([[NSUserDefaults standardUserDefaults] integerForKey: @"PreferredViewStyle"  default: GNUMailDrawerView] == GNUMailFloatingView)
2167    {
2168      [[[MailboxManagerController singleInstance] window] close];
2169    }
2170
2171  RELEASE([MailboxManagerController singleInstance]);
2172
2173  // We close our Console
2174  [[[ConsoleWindowController singleInstance] window] close];
2175  RELEASE([ConsoleWindowController singleInstance]);
2176
2177  // We release our current working path
2178  TEST_RELEASE(currentWorkingPath);
2179
2180  // We release our array containing all our bundles
2181  RELEASE(allBundles);
2182
2183  // We release our array containing our password cache
2184  RELEASE([Utilities passwordCache]);
2185
2186  // We release our MimeType, our Filters and our AddressBook
2187  RELEASE([MimeTypeManager singleInstance]);
2188  RELEASE([FilterManager singleInstance]);
2189  RELEASE([AddressBookController singleInstance]);
2190
2191  // We stop our task manager
2192  [(TaskManager *)[TaskManager singleInstance] stop];
2193
2194  // We finally remove all temporary files and then, we are ready to really close the application.
2195  [self removeTemporaryFiles];
2196
2197  // We restore the application image under OS X since if we have drawn to it (by showing
2198  // the unread messages count), this image will stay put.
2199#ifdef MACOSX
2200  [NSApp setApplicationIconImage: [NSImage imageNamed: @"NSApplicationIcon"]];
2201#endif
2202
2203  return NSTerminateNow;
2204}
2205
2206
2207//
2208//
2209//
2210- (void) applicationWillFinishLaunching: (NSNotification *) theNotification
2211{
2212#ifdef MACOSX
2213  // We begin by setting our NSApp's icon
2214  [ApplicationIconController singleInstance];
2215#else
2216  SEL action = NULL;
2217  unichar del, up, down;
2218  NSMenuItem *tempMenuItem;
2219
2220  del = NSDeleteCharacter;       // FIXME: We might want to display, instead:
2221  up = NSUpArrowFunctionKey;     // 8593 (0x2191) U+2191 arrowup UPWARDS ARROW
2222  down = NSDownArrowFunctionKey; // 8595 (0x2193) U+2193 arrowup DOWNWARDS ARROW
2223
2224  // We begin by setting our NSApp's icon
2225  [ApplicationIconController singleInstance];
2226
2227  // We continue by creating our NSMenu
2228  menu = [[NSMenu alloc] init];
2229
2230  [menu addItemWithTitle: _(@"Info")
2231	action: action
2232	keyEquivalent: @""];
2233  [menu addItemWithTitle: _(@"Message")
2234	action: action
2235	keyEquivalent: @""];
2236  [menu addItemWithTitle: _(@"Mailbox")
2237	action: action
2238	keyEquivalent: @""];
2239  [menu addItemWithTitle: _(@"Edit")
2240	action: action
2241	keyEquivalent: @""];
2242  [menu addItemWithTitle: _(@"Find")
2243	action: action
2244	keyEquivalent: @""];
2245  [menu addItemWithTitle: _(@"View")
2246	action: action
2247	keyEquivalent: @""];
2248  [menu addItemWithTitle: _(@"Windows")
2249	action: action
2250	keyEquivalent: @""];
2251
2252  // We verify if scrippting is supported by the application.
2253  if ( [NSApp isScriptingSupported] )
2254    {
2255      [menu addItemWithTitle: _(@"Scripting")
2256	    action: action
2257	    keyEquivalent: @""];
2258    }
2259
2260  [menu addItemWithTitle: _(@"Services")
2261	action: action
2262	keyEquivalent: @""];
2263  [menu addItemWithTitle: _(@"Hide")
2264	action: @selector (hide:)
2265	keyEquivalent: @"h"];
2266  [menu addItemWithTitle: _(@"Quit")
2267	action: @selector(terminate:)
2268	keyEquivalent: @"q"];
2269
2270  //
2271  // Info menu / submenus
2272  //
2273  info = [[NSMenu alloc] init];
2274  [menu setSubmenu: info  forItem: [menu itemWithTitle: _(@"Info")]];
2275  [info addItemWithTitle: _(@"About GNUMail...")
2276	action: @selector(showAboutPanel:)
2277	keyEquivalent: @""];
2278  [info addItemWithTitle: _(@"Check for Updates...")
2279	action: @selector(checkForUpdates:)
2280	keyEquivalent: @""];
2281  [info addItemWithTitle: _(@"Preferences...")
2282	action: @selector(showPreferencesWindow:)
2283	keyEquivalent: @","];
2284  [info addItemWithTitle: _(@"Help...")
2285	action: action
2286	keyEquivalent: @"?"];
2287  RELEASE(info);
2288
2289
2290  //
2291  // Our Message menu / submenus
2292  //
2293  message = [[NSMenu alloc] init];
2294  [menu setSubmenu: message  forItem: [menu itemWithTitle: _(@"Message")]];
2295
2296  [message addItemWithTitle: _(@"Compose")
2297	   action: @selector(composeMessage:)
2298	   keyEquivalent: @"n"];
2299
2300  //
2301  // Our reply submenu
2302  //
2303  [message addItemWithTitle: _(@"Reply")
2304	   action: action
2305	   keyEquivalent: @""];
2306
2307  reply = [[NSMenu alloc] init];
2308  [message setSubmenu: reply  forItem: [message itemWithTitle: _(@"Reply")]];
2309
2310  [reply addItemWithTitle: _(@"Normal")
2311	 action: @selector(replyToMessage:)
2312	 keyEquivalent: @"R"];
2313  [[reply itemAtIndex: 0] setTag: PantomimeNormalReplyMode];
2314  [reply addItemWithTitle: _(@"Simple")
2315	 action: @selector(replyToMessage:)
2316	 keyEquivalent: @""];
2317  [[reply itemAtIndex: 1] setTag: PantomimeSimpleReplyMode];
2318  [reply addItemWithTitle: _(@"All")
2319	 action: @selector(replyToMessage:)
2320	 keyEquivalent: @"E"];
2321  [[reply itemAtIndex: 2] setTag: (PantomimeNormalReplyMode|PantomimeReplyAllMode)];
2322
2323
2324  //
2325  // Our forward submenu
2326  //
2327  [message addItemWithTitle: _(@"Forward")
2328	   action: action
2329	   keyEquivalent: @""];
2330
2331  forward = [[NSMenu alloc] init];
2332  [message setSubmenu: forward  forItem: [message itemWithTitle: _(@"Forward")]];
2333
2334  [forward addItemWithTitle: _(@"Attachment")
2335	   action: @selector(forwardMessage:)
2336	   keyEquivalent: @""];
2337  [[forward itemAtIndex: 0] setTag: PantomimeAttachmentForwardMode];
2338  [forward addItemWithTitle: _(@"Inline")
2339	   action: @selector(forwardMessage:)
2340	   keyEquivalent: @"W"];
2341  [[forward itemAtIndex: 1] setTag: PantomimeInlineForwardMode];
2342  RELEASE(forward);
2343
2344  [message addItemWithTitle: _(@"Redirect")
2345	   action: @selector(redirectMessage:)
2346	   keyEquivalent: @""];
2347
2348  [message addItemWithTitle: _(@"Make Filter from")
2349	             action: action
2350	   keyEquivalent: @""];
2351
2352  //
2353  // Submenu for creating filter rules from messages
2354  //
2355  messageFilter = [[NSMenu alloc] init];
2356  [message setSubmenu: messageFilter forItem: [message itemWithTitle: _(@"Make Filter from")]];
2357  [messageFilter addItemWithTitle: _(@"Sender")
2358		 action: @selector(makeFilterFromSender:)
2359		 keyEquivalent: @""];
2360  [messageFilter addItemWithTitle: _(@"To")
2361                           action: @selector(makeFilterFromTo:)
2362                    keyEquivalent: @""];
2363  [messageFilter addItemWithTitle: _(@"Cc")
2364                           action: @selector(makeFilterFromCc:)
2365                    keyEquivalent: @""];
2366  [messageFilter addItemWithTitle: _(@"List-Id")
2367                           action: @selector(makeFilterFromListId:)
2368                    keyEquivalent: @""];
2369  [messageFilter addItemWithTitle: _(@"Subject")
2370		 action: @selector(makeFilterFromSubject:)
2371		 keyEquivalent: @""];
2372
2373  RELEASE(messageFilter);
2374
2375  tempMenuItem = [[NSMenuItem alloc] init];
2376  [tempMenuItem setTitle: _(@"Deliver")];
2377  [tempMenuItem setAction: @selector(sendMessage:)];
2378  [tempMenuItem setKeyEquivalent: @"D"];
2379  [message addItem: tempMenuItem];
2380  RELEASE(tempMenuItem);
2381
2382  tempMenuItem = [[NSMenuItem alloc] init];
2383  [tempMenuItem setTitle: _(@"Mark as Read")];
2384  [tempMenuItem setAction: @selector(markMessageAsReadOrUnread:)];
2385  [tempMenuItem setKeyEquivalent: @"U"];
2386  [message addItem: tempMenuItem];
2387  RELEASE(tempMenuItem);
2388
2389  tempMenuItem = [[NSMenuItem alloc] init];
2390  [tempMenuItem setTitle: _(@"Mark as Flagged")];
2391  [tempMenuItem setAction: @selector(markMessageAsFlaggedOrUnflagged:)];
2392  [tempMenuItem setKeyEquivalent: @""];
2393  [message addItem: tempMenuItem];
2394  RELEASE(tempMenuItem);
2395
2396  tempMenuItem = [[NSMenuItem alloc] init];
2397  [tempMenuItem setTitle: _(@"Undelete")];
2398  [tempMenuItem setAction: @selector(deleteMessage:)];
2399  [tempMenuItem setKeyEquivalent: [NSString stringWithCharacters: &del  length: 1]];
2400  [message addItem: tempMenuItem];
2401  RELEASE(tempMenuItem);
2402
2403  [message addItemWithTitle: _(@"Save")
2404	   action: action
2405	   keyEquivalent: @""];
2406
2407  save = [[NSMenu alloc] init];
2408  [message setSubmenu: save  forItem: [message itemWithTitle: _(@"Save")]];
2409  [save addItemWithTitle: _(@"Text from Message")
2410	action: @selector(saveTextFromMessage:)
2411	keyEquivalent: @""];
2412  RELEASE(save);
2413
2414  [message addItemWithTitle: _(@"Drafts")
2415	   action: action
2416	   keyEquivalent: @""];
2417
2418  //
2419  //
2420  //
2421  drafts = [[NSMenu alloc] init];
2422  tempMenuItem = [[NSMenuItem alloc] initWithTitle: _(@"Save in Drafts")
2423				     action: @selector(saveInDrafts:)
2424				     keyEquivalent: @"s"];
2425  [drafts addItem: tempMenuItem];
2426  RELEASE(tempMenuItem);
2427
2428  [drafts addItemWithTitle: _(@"Restore Draft")
2429	  action: @selector(restoreDraft:)
2430	  keyEquivalent: @""];
2431  [[message itemWithTitle: _(@"Drafts")] setSubmenu: drafts];
2432  RELEASE(drafts);
2433
2434  [message addItemWithTitle: _(@"Text Encodings")
2435	   action: action
2436	   keyEquivalent: @""];
2437
2438  textEncodings = [[NSMenu alloc] init];
2439  [message setSubmenu: textEncodings  forItem: [message itemWithTitle: _(@"Text Encodings")]];
2440  RELEASE(textEncodings);
2441
2442  [message addItemWithTitle: _(@"Add Sender to Address Book")
2443	   action: @selector(addSenderToAddressBook:)
2444	   keyEquivalent: @""];
2445
2446  [message addItemWithTitle: _(@"Apply Manual Filters")
2447	   action: action
2448	   keyEquivalent: @""];
2449
2450  filters = [[NSMenu alloc] init];
2451  [[message itemWithTitle: _(@"Apply Manual Filters")] setSubmenu: filters];
2452  RELEASE(filters);
2453
2454  [message addItemWithTitle: _(@"Print...")
2455	   action: @selector(printMessage:)
2456	   keyEquivalent: @"p"];
2457  RELEASE(message);
2458
2459  //
2460  // Mailbox menu / submenus
2461  //
2462  mailbox = [[NSMenu alloc] init];
2463  [menu setSubmenu: mailbox  forItem: [menu itemWithTitle: _(@"Mailbox")]];
2464  [mailbox addItemWithTitle: _(@"Mailboxes...")
2465	   action: @selector(showMailboxManager:)
2466	   keyEquivalent: @"M"];
2467
2468  incomingMailServers = [[NSMenu alloc] init];
2469  [mailbox addItemWithTitle: _(@"Get New Mail")
2470	   action: action
2471	   keyEquivalent: @""];
2472  [[mailbox itemAtIndex: 1] setSubmenu: incomingMailServers];
2473  RELEASE(incomingMailServers);
2474
2475  [mailbox addItemWithTitle: _(@"New Viewer Window")
2476	   action: @selector(newViewerWindow:)
2477	   keyEquivalent: @""];
2478  [mailbox addItemWithTitle: _(@"Import Mailboxes...")
2479	   action: @selector(importMailboxes:)
2480	   keyEquivalent: @""];
2481  [mailbox addItemWithTitle: _(@"Inspector...")
2482	   action: @selector(showMailboxInspectorPanel:)
2483	   keyEquivalent: @""];
2484  [mailbox addItemWithTitle: _(@"Compact...")
2485	   action: @selector(compactMailbox:)
2486	   keyEquivalent: @"K"];
2487  RELEASE(mailbox);
2488
2489
2490  //
2491  // Edit menu / submenus
2492  //
2493  edit = [[NSMenu alloc] init];
2494  [menu setSubmenu: edit  forItem: [menu itemWithTitle: _(@"Edit")]];
2495
2496  [edit addItemWithTitle: _(@"Cut")
2497	action: @selector(cut:)
2498	keyEquivalent: @"x"];
2499  [edit addItemWithTitle: _(@"Copy")
2500	action: @selector(copy:)
2501	keyEquivalent: @"c"];
2502  [edit addItemWithTitle: _(@"Paste")
2503	action: @selector(paste:)
2504	keyEquivalent: @"v"];
2505  [edit addItemWithTitle: _(@"Paste As Quoted Text")
2506	action: @selector(pasteAsQuoted:)
2507	keyEquivalent: @"V"];
2508  [edit addItemWithTitle: _(@"Undo")
2509	action: action
2510	keyEquivalent: @"z"];
2511  [edit addItemWithTitle: _(@"Spelling...")
2512	action: @selector(checkSpelling:)
2513	keyEquivalent: @":"];
2514  [edit addItemWithTitle: _(@"Check Spelling")
2515	action: @selector(showGuessPanel:)
2516	keyEquivalent: @";"];
2517  [edit addItemWithTitle: _(@"Select All")
2518	action: @selector(selectAll:)
2519	keyEquivalent: @"a"];
2520
2521  selectAllMessagesInThread = [[NSMenuItem alloc] initWithTitle: _(@"Select All Messages in Thread")
2522	action: @selector(selectAllMessagesInThread:)
2523	keyEquivalent: @""];
2524  [edit addItem: selectAllMessagesInThread];
2525  RELEASE(selectAllMessagesInThread);
2526  RELEASE(edit);
2527
2528
2529  //
2530  // Find menu / submenus
2531  //
2532  find = [[NSMenu alloc] init];
2533  [menu setSubmenu: find  forItem: [menu itemWithTitle: _(@"Find")]];
2534
2535  [find addItemWithTitle: _(@"Find Messages...")
2536	action: @selector(showFindWindow:)
2537	keyEquivalent: @"F"];
2538  [find addItemWithTitle: _(@"Find Text...")
2539	action: action
2540	keyEquivalent: @"f"];
2541  [find addItemWithTitle: _(@"Find Next")
2542	action: @selector(findNext:)
2543	keyEquivalent: @"g"];
2544  [find addItemWithTitle: _(@"Find Previous")
2545	action: @selector(findPrevious:)
2546	keyEquivalent: @"d"];
2547
2548  enterSelection = [[NSMenuItem alloc] initWithTitle: _(@"Enter Selection")
2549				       action: action
2550				       keyEquivalent: @"e"];
2551  [find addItem: enterSelection];
2552  RELEASE(enterSelection);
2553  RELEASE(find);
2554
2555
2556  //
2557  // Our View menu / submenus
2558  //
2559  view =  [[NSMenu alloc] init];
2560  [menu setSubmenu: view  forItem: [menu itemWithTitle: _(@"View")]];
2561
2562  threadOrUnthreadMessages = [[NSMenuItem alloc] init];
2563  [threadOrUnthreadMessages setTitle: _(@"Thread Messages")];
2564  [threadOrUnthreadMessages setAction: @selector(threadOrUnthreadMessages:)];
2565  [threadOrUnthreadMessages setKeyEquivalent: @""];
2566  [threadOrUnthreadMessages setTag: THREAD_MESSAGES];
2567  [view addItem: threadOrUnthreadMessages];
2568  RELEASE(threadOrUnthreadMessages);
2569
2570  [view addItemWithTitle: _(@"Columns")
2571	action: action
2572	keyEquivalent: @""];
2573
2574  columns = [[NSMenu alloc] init];
2575  [[view itemAtIndex: 1] setSubmenu: columns];
2576
2577  [columns addItemWithTitle: _(@"Date")
2578	   action: @selector(showOrHideTableColumns:)
2579	   keyEquivalent: @""];
2580  [columns addItemWithTitle: _(@"Flags")
2581	   action: @selector(showOrHideTableColumns:)
2582	   keyEquivalent: @""];
2583  [columns addItemWithTitle: _(@"From")
2584	   action: @selector(showOrHideTableColumns:)
2585	   keyEquivalent: @""];
2586  [columns addItemWithTitle: _(@"Number")
2587	   action: @selector(showOrHideTableColumns:)
2588	   keyEquivalent: @""];
2589  [columns addItemWithTitle: _(@"Size")
2590	   action: @selector(showOrHideTableColumns:)
2591	   keyEquivalent: @""];
2592  [columns addItemWithTitle: _(@"Status")
2593	   action: @selector(showOrHideTableColumns:)
2594	   keyEquivalent: @""];
2595  [columns addItemWithTitle: _(@"Subject")
2596	   action: @selector(showOrHideTableColumns:)
2597	   keyEquivalent: @""];
2598  [[columns itemAtIndex: 0] setTag: GNUMailDateColumn];
2599  [[columns itemAtIndex: 1] setTag: GNUMailFlagsColumn];
2600  [[columns itemAtIndex: 2] setTag: GNUMailFromColumn];
2601  [[columns itemAtIndex: 3] setTag: GNUMailNumberColumn];
2602  [[columns itemAtIndex: 4] setTag: GNUMailSizeColumn];
2603  [[columns itemAtIndex: 5] setTag: GNUMailStatusColumn];
2604  [[columns itemAtIndex: 6] setTag: GNUMailSubjectColumn];
2605  RELEASE(columns);
2606
2607  [view addItemWithTitle: _(@"Sorting")
2608	action: action
2609	keyEquivalent: @""];
2610
2611  sorting = [[NSMenu alloc] init];
2612  [[view itemAtIndex: 2] setSubmenu: sorting];
2613
2614  [sorting addItemWithTitle: _(@"Sort by Date")
2615	   action: @selector(sortByDate:)
2616	   keyEquivalent: @""];
2617  [sorting addItemWithTitle: _(@"Sort by Name")
2618	   action: @selector(sortByName:)
2619	   keyEquivalent: @"S"];
2620  [sorting addItemWithTitle: _(@"Sort by Number")
2621	   action: @selector(sortByNumber:)
2622	   keyEquivalent: @""];
2623  [sorting addItemWithTitle: _(@"Sort by Size")
2624	   action: @selector(sortBySize:)
2625	   keyEquivalent: @""];
2626  [sorting addItemWithTitle: _(@"Sort by Subject")
2627	   action: @selector(sortBySubject:)
2628	   keyEquivalent: @""];
2629  RELEASE(sorting);
2630
2631  tempMenuItem = [[NSMenuItem alloc] init];
2632  [tempMenuItem setTitle: _(@"Hide Deleted")];
2633  [tempMenuItem setAction: @selector(showOrHideDeletedMessages:)];
2634  [tempMenuItem setKeyEquivalent: @""];
2635  [tempMenuItem setTag: HIDE_DELETED_MESSAGES];
2636  [view addItem: tempMenuItem];
2637  RELEASE(tempMenuItem);
2638
2639  tempMenuItem = [[NSMenuItem alloc] init];
2640  [tempMenuItem setTitle: _(@"Hide Read")];
2641  [tempMenuItem setAction: @selector(showOrHideReadMessages:)];
2642  [tempMenuItem setKeyEquivalent: @""];
2643  [tempMenuItem setTag: HIDE_READ_MESSAGES];
2644  [view addItem: tempMenuItem];
2645  RELEASE(tempMenuItem);
2646
2647  tempMenuItem = [[NSMenuItem alloc] init];
2648  [tempMenuItem setTitle: _(@"All Headers")];
2649  [tempMenuItem setAction: @selector(showAllHeaders:)];
2650  [tempMenuItem setKeyEquivalent: @""];
2651  [tempMenuItem setTag: SHOW_ALL_HEADERS];
2652  [view addItem: tempMenuItem];
2653  RELEASE(tempMenuItem);
2654
2655  tempMenuItem = [[NSMenuItem alloc] init];
2656  [tempMenuItem setTitle: _(@"Raw Source")];
2657  [tempMenuItem setAction: @selector(showRawSource:)];
2658  [tempMenuItem setKeyEquivalent: @""];
2659  [view addItem: tempMenuItem];
2660  RELEASE(tempMenuItem);
2661
2662  [view addItemWithTitle: _(@"Previous Unread")
2663	action: @selector(previousUnreadMessage:)
2664	keyEquivalent: [NSString stringWithCharacters: &up  length: 1]];
2665  [[view itemWithTitle: _(@"Previous Unread")] setKeyEquivalentModifierMask: NSControlKeyMask];
2666
2667  [view addItemWithTitle: _(@"Next Unread")
2668	action: @selector(nextUnreadMessage:)
2669	keyEquivalent: [NSString stringWithCharacters: &down  length: 1]];
2670  [[view itemWithTitle: _(@"Next Unread")] setKeyEquivalentModifierMask: NSControlKeyMask];
2671
2672  showOrHideToolbar = [[NSMenuItem alloc] init];
2673  [showOrHideToolbar setTitle: _(@"Hide Toolbar")];
2674  [showOrHideToolbar setAction: @selector(showOrHideToolbar:)];
2675  [showOrHideToolbar setKeyEquivalent: @""];
2676  [view addItem: showOrHideToolbar];
2677  RELEASE(showOrHideToolbar);
2678
2679  customizeToolbar = [[NSMenuItem alloc] init];
2680  [customizeToolbar setTitle: _(@"Customize Toolbar...")];
2681  [customizeToolbar setAction: @selector(customizeToolbar:)];
2682  [customizeToolbar setKeyEquivalent: @""];
2683  [view addItem: customizeToolbar];
2684  RELEASE(customizeToolbar);
2685
2686  RELEASE(view);
2687
2688
2689  //
2690  // Windows menu
2691  //
2692  windows = [[NSMenu alloc] init];
2693  [menu setSubmenu: windows  forItem: [menu itemWithTitle: _(@"Windows")]];
2694  [windows addItemWithTitle: _(@"Address Book")
2695	   action: @selector(showAddressBook:)
2696	   keyEquivalent: @"A"];
2697  [windows addItemWithTitle: _(@"Console")
2698	   action: @selector(showConsoleWindow:)
2699	   keyEquivalent: @"C"];
2700  [windows addItemWithTitle: _(@"Arrange")
2701	   action: @selector(arrangeInFront:)
2702	   keyEquivalent: @""];
2703  [windows addItemWithTitle: _(@"Miniaturize")
2704	   action: @selector(performMiniaturize:)
2705	   keyEquivalent: @"m"];
2706  [windows addItemWithTitle: _(@"Close")
2707	   action: @selector(close:)
2708	   keyEquivalent: @"w"];
2709  RELEASE(windows);
2710
2711  if ([NSApp isScriptingSupported])
2712    {
2713      [menu setSubmenu: [NSApp scriptingMenu]
2714	    forItem: [menu itemWithTitle: _(@"Scripting")]];
2715    }
2716
2717  // Our Services menu
2718  services = [[NSMenu alloc] init];
2719  [menu setSubmenu: services  forItem: [menu itemWithTitle: _(@"Services")]];
2720  [NSApp setServicesMenu: services];
2721  RELEASE(services);
2722
2723  [NSApp setMainMenu: menu];
2724  [NSApp setWindowsMenu: windows];
2725  RELEASE(menu);
2726#endif
2727}
2728
2729
2730//
2731//
2732//
2733- (void) applicationDidFinishLaunching: (NSNotification *) theNotification
2734{
2735  NSUserDefaults *aUserDefaults;
2736  NSString *pathToLocalMailDir;
2737  NSFileManager *aFileManager;
2738  CWLocalStore *aLocalStore;
2739
2740  BOOL isDir, mustShowPreferencesWindow;
2741
2742  aUserDefaults = [NSUserDefaults standardUserDefaults];
2743  aFileManager = [NSFileManager defaultManager];
2744  mustShowPreferencesWindow = NO;
2745  aLocalStore = nil;
2746
2747  //
2748  // We check we if must update our view style
2749  //
2750  if ([aUserDefaults objectForKey: @"PreferredViewStyleAfterRestart"])
2751    {
2752      [aUserDefaults setInteger: [aUserDefaults integerForKey: @"PreferredViewStyleAfterRestart"]
2753		     forKey: @"PreferredViewStyle"];
2754      [aUserDefaults removeObjectForKey: @"PreferredViewStyleAfterRestart"];
2755    }
2756
2757  // We now verify if the User's Library directory does exist (to store
2758  // the AddressBook, the MimeTypes, etc) and if not, we create it.
2759  if ([aFileManager fileExistsAtPath: (NSString *)GNUMailUserLibraryPath()
2760		    isDirectory: &isDir])
2761    {
2762      if (!isDir)
2763	{
2764	  NSRunCriticalAlertPanel(_(@"Fatal error!"),
2765				  _(@"%@ exists but it is a file not a directory.\nThe application will now terminate."),
2766				  @"OK",
2767				  NULL,
2768				  NULL,
2769				  GNUMailUserLibraryPath());
2770	  exit(1);
2771	}
2772    }
2773  else
2774    {
2775      if (![aFileManager createDirectoryAtPath: (NSString *)GNUMailUserLibraryPath()
2776			 attributes: nil] )
2777	{
2778	  // Directory creation failed. We warn the user, then quit.
2779	  NSRunCriticalAlertPanel(_(@"Fatal error!"),
2780				  _(@"Could not create directory: %@\nThe application will now terminate."),
2781				  @"OK",
2782				  NULL,
2783				  NULL,
2784				  GNUMailUserLibraryPath());
2785	  exit(1);
2786	}
2787    }
2788
2789  [[NSNotificationCenter defaultCenter]
2790    addObserver: self
2791    selector: @selector(_updateGetNewMailMenuItems:)
2792    name: AccountsHaveChanged
2793    object: nil];
2794
2795  [[NSNotificationCenter defaultCenter]
2796    addObserver: self
2797    selector: @selector(_updateFilterMenuItems:)
2798    name: FiltersHaveChanged
2799    object: nil];
2800
2801  [[NSNotificationCenter defaultCenter]
2802    addObserver: self
2803    selector: @selector(selectionInTextViewHasChanged:)
2804    name: NSTextViewDidChangeSelectionNotification
2805    object: nil];
2806
2807  // We initialize our mutable array containing all open EditWindow:s
2808  allEditWindows = [[NSMutableArray alloc] init];
2809  // and their controllers
2810  allEditWindowControllers = [[NSMutableArray alloc] init];
2811
2812  // We initialize our mutable array containing all open MailWindow:s
2813  allMailWindows = [[NSMutableArray alloc] init];
2814  // and their controllers
2815  allMailWindowControllers = [[NSMutableArray alloc] init];
2816
2817  // We initialize our mutable array containing all our bundles
2818  allBundles = [[NSMutableArray alloc] init];
2819
2820  // We set the current working path of GNUMail to the user's home directory
2821  [GNUMail setCurrentWorkingPath: NSHomeDirectory()];
2822
2823
2824  // Setup our mailbox locations, if LOCALMAILDIR isn't defined, we define
2825  // it to ~/Mailboxes (if the mbox format is used, ~/Maildir otherwise)
2826  // under GNUstep and to ~/Library/GNUMail/Mailboxes under Mac OS X
2827  if (![[NSUserDefaults standardUserDefaults] objectForKey: @"LOCALMAILDIR"])
2828    {
2829#ifdef MACOSX
2830      pathToLocalMailDir = [NSHomeDirectory() stringByAppendingPathComponent: @"Library/GNUMail/Mailboxes"];
2831#else
2832      pathToLocalMailDir = [NSHomeDirectory() stringByAppendingPathComponent: @"Mailboxes"];
2833#endif
2834
2835      [[NSUserDefaults standardUserDefaults] setObject: pathToLocalMailDir  forKey: @"LOCALMAILDIR"];
2836      [[NSUserDefaults standardUserDefaults] setObject: pathToLocalMailDir  forKey: @"LOCALMAILDIR_PREVIOUS"];
2837    }
2838  else
2839    {
2840      NSString *aString;
2841
2842      pathToLocalMailDir = [[NSUserDefaults standardUserDefaults] objectForKey: @"LOCALMAILDIR"];
2843
2844      // We remove the trailing slash, if any.
2845      if ([pathToLocalMailDir length] > 1 && [pathToLocalMailDir hasSuffix: @"/"])
2846	{
2847	  pathToLocalMailDir = [pathToLocalMailDir substringToIndex: ([pathToLocalMailDir length] - 1)];
2848	  [[NSUserDefaults standardUserDefaults] setObject: pathToLocalMailDir forKey: @"LOCALMAILDIR"];
2849	}
2850
2851      // If LOCALMAILDIR_PREVIOUS isn't set, we set it to LOCALMAILDIR
2852      if (![[NSUserDefaults standardUserDefaults] objectForKey: @"LOCALMAILDIR_PREVIOUS"])
2853	{
2854	  [[NSUserDefaults standardUserDefaults] setObject: pathToLocalMailDir  forKey: @"LOCALMAILDIR_PREVIOUS"];
2855	}
2856
2857      aString = [[NSUserDefaults standardUserDefaults] objectForKey: @"LOCALMAILDIR_PREVIOUS"];
2858
2859#warning IF THE DESTINATION PATH ALREADY EXISTS, WARN AND QUIT THE APP
2860      if (![pathToLocalMailDir isEqualToString: aString])
2861	{
2862	  [self moveLocalMailDirectoryFromPath: aString  toPath: pathToLocalMailDir];
2863	}
2864    }
2865
2866  //
2867  // We migrate our preferences (and other things) from previous GNUMail versions.
2868  // Currently, we can migrate from:  1.1.2 to 1.2.0
2869  //
2870  [self update_112_to_120];
2871
2872  //
2873  // We verify if GNUMail has been configured, if not, we suggest the user to do so.
2874  //
2875  if (![[NSUserDefaults standardUserDefaults] objectForKey: @"ACCOUNTS"])
2876    {
2877      NSMutableDictionary *allValues, *theAccount;
2878      WelcomePanel *aWelcomePanel;
2879      int type;
2880
2881      aWelcomePanel = [[WelcomePanel alloc] init];
2882      [aWelcomePanel layoutWindow];
2883
2884      if ([NSApp runModalForWindow: aWelcomePanel] == NSRunAbortedResponse)
2885	{
2886	  [NSApp terminate: self];
2887	}
2888
2889      type = ([[aWelcomePanel matrix] selectedRow] ? PantomimeFormatMaildir : PantomimeFormatMbox);
2890
2891      RELEASE(aWelcomePanel);
2892
2893      // We create the mailboxes directory for GNUMail
2894      if (![[NSFileManager defaultManager]
2895	     fileExistsAtPath: pathToLocalMailDir
2896	     isDirectory: &isDir])
2897	{
2898	  [[NSFileManager defaultManager] createDirectoryAtPath: pathToLocalMailDir
2899					  attributes: nil];
2900	}
2901      else
2902	{
2903	  // If it's a file
2904	  if (!isDir)
2905	    {
2906	      NSRunAlertPanel(_(@"Error!"),
2907			      _(@"%@ is a file and not a directory. Please remove that file before restarting GNUMail."),
2908			      _(@"OK"),
2909			      NULL,
2910			      NULL,
2911			      pathToLocalMailDir);
2912	      [NSApp terminate: self];
2913	    }
2914	}
2915
2916      //
2917      // We create the following Mailboxes automatically, only if we need to:
2918      //
2919      // - Inbox  : for the newly received messages
2920      // - Sent   : for the messages that have been sent
2921      // - Trash  : for the messages we want to delete and transfer locally in IMAP
2922      // - Drafts : for un-sent messages
2923      //
2924      aLocalStore = [[CWLocalStore alloc] initWithPath: pathToLocalMailDir];
2925
2926      [aLocalStore createFolderWithName: @"Inbox"
2927		   type: type
2928		   contents: [NSData dataWithContentsOfFile: [NSString stringWithFormat: @"%@/Welcome", [[NSBundle mainBundle] resourcePath]]]];
2929
2930      [aLocalStore createFolderWithName: @"Sent"
2931		   type: type
2932		   contents: nil];
2933
2934      [aLocalStore createFolderWithName: @"Trash"
2935		   type: type
2936		   contents: nil];
2937
2938      [aLocalStore createFolderWithName: @"Drafts"
2939		   type: type
2940		   contents: nil];
2941
2942      if (type == PantomimeFormatMaildir)
2943	{
2944	  [[NSUserDefaults standardUserDefaults] setInteger: 1  forKey: @"UseMaildirMailboxFormat"];
2945	}
2946
2947      //
2948      // We create a basic account with default preferences values just to get the user started.
2949      //
2950      theAccount = [[NSMutableDictionary alloc] init];
2951
2952
2953      //
2954      // We set the default PERSONAL values.
2955      //
2956      allValues = [[NSMutableDictionary alloc] init];
2957      [allValues setObject: _(@"Your name")           forKey: @"NAME"];
2958      [allValues setObject: _(@"Your E-Mail address") forKey: @"EMAILADDR"];
2959      [theAccount setObject: allValues  forKey: @"PERSONAL"];
2960      RELEASE(allValues);
2961
2962      //
2963      // MAILBOXES, we set the INBOX, SENT, .. for this account.
2964      //
2965      allValues = [[NSMutableDictionary alloc] init];
2966      [allValues setObject: [NSString stringWithFormat: @"local://%@", [pathToLocalMailDir stringByAppendingPathComponent: @"Inbox"]]   forKey: @"INBOXFOLDERNAME"];
2967      [allValues setObject: [NSString stringWithFormat: @"local://%@", [pathToLocalMailDir stringByAppendingPathComponent: @"Sent"]]    forKey: @"SENTFOLDERNAME"];
2968      [allValues setObject: [NSString stringWithFormat: @"local://%@", [pathToLocalMailDir stringByAppendingPathComponent: @"Drafts"]]  forKey: @"DRAFTSFOLDERNAME"];
2969      [allValues setObject: [NSString stringWithFormat: @"local://%@", [pathToLocalMailDir stringByAppendingPathComponent: @"Trash"]]   forKey: @"TRASHFOLDERNAME"];
2970      [theAccount setObject: allValues  forKey: @"MAILBOXES"];
2971      RELEASE(allValues);
2972
2973      //
2974      // SEND, we set the transport method to SMTP
2975      //
2976      allValues = [[NSMutableDictionary alloc] init];
2977      [allValues setObject: [NSNumber numberWithInt: 2]  forKey: @"TRANSPORT_METHOD"];
2978      [allValues setObject: @"smtp.server.com"  forKey: @"SMTP_HOST"];
2979      [theAccount setObject: allValues  forKey: @"SEND"];
2980      RELEASE(allValues);
2981
2982      //
2983      // We finally save the account's information
2984      //
2985      [[NSUserDefaults standardUserDefaults] setObject: [NSDictionary dictionaryWithObject: theAccount
2986								      forKey: @"General"]
2987					     forKey: @"ACCOUNTS"];
2988      RELEASE(theAccount);
2989
2990      //
2991      // We create the basic set of shown headers and other preference values.
2992      //
2993      [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects: @"Date", @"From", @"To", @"Cc", @"Subject", nil]
2994					     forKey: @"SHOWNHEADERS"];
2995      [[NSUserDefaults standardUserDefaults] setBool: YES  forKey: @"HIDE_DELETED_MESSAGES"];
2996      [[NSUserDefaults standardUserDefaults] setBool: YES  forKey: @"HIGHLIGHT_URL"];
2997
2998      //
2999      // We add our "Inbox" folder to the list of folders to open.
3000      //
3001      [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObject: [NSString stringWithFormat: @"local://%@",
3002											    [pathToLocalMailDir stringByAppendingPathComponent: @"Inbox"]]]
3003					     forKey: @"FOLDERS_TO_OPEN"];
3004
3005      mustShowPreferencesWindow = YES;
3006    } // if ( ![[NSUserDefaults standardUserDefaults] objectForKey: @"ACCOUNTS"] )
3007
3008
3009  //
3010  // We initialize our store
3011  //
3012  if (!aLocalStore)
3013    {
3014      aLocalStore = [[CWLocalStore alloc] initWithPath: pathToLocalMailDir];
3015    }
3016
3017  if (!aLocalStore)
3018    {
3019      NSString *aString;
3020
3021#ifdef MACOSX
3022      aString = _(@"Could not open the Local Store.\nThat means GNUMail is not properly configured.\nTo fix this problem, do the following commands:\n\n%% mkdir ~/Library/GNUMail/Mailboxes\n%% touch ~/Library/GNUMail/Mailboxes/Inbox\n%% touch ~/Library/GNUMail/Mailboxes/Sent\n%% touch ~/Library/GNUMail/Mailboxes/Trash\n%% touch ~/Library/GNUMail/Mailboxes/Drafts\n\nand restart GNUMail after that! You can also remove the ~/Library/Preferences/com.collaboration-world.GNUMail.plist file instead of doing the commands mentioned above.");
3023#else
3024      aString = _(@"Could not open the Local Store.\nThat means GNUMail is not properly configured.\nTo fix this problem, do the following commands:\n\n%% mkdir ~/Mailboxes\n%% touch ~/Mailboxes/Inbox\n%% touch ~/Mailboxes/Sent\n%% touch ~/Mailboxes/Trash\n%% touch ~/Mailboxes/Drafts\n\nand restart GNUMail after that!");
3025#endif
3026
3027      NSRunCriticalAlertPanel(_(@"Fatal error!"),
3028			      aString,
3029			      @"OK",
3030			      NULL,
3031			      NULL);
3032
3033      [NSApp terminate: self];
3034    }
3035
3036  [aLocalStore setDelegate: [TaskManager singleInstance]];
3037
3038  // We got a valid Local store, let's add it to our list of open Store:s in the MailboxManagerController
3039  [[MailboxManagerController singleInstance] setStore: aLocalStore
3040					     name: @"GNUMAIL_LOCAL_STORE"
3041					     username: NSUserName()];
3042
3043  [[MailboxManagerController singleInstance] reloadAllFolders];
3044
3045  // Now we set the target to our items for creating/deleting/renaming mailboxes
3046#ifdef MACOSX
3047  [create setTarget: [MailboxManagerController singleInstance]];
3048  [create setAction: @selector(create:)];
3049  [delete setTarget: [MailboxManagerController singleInstance]];
3050  [delete setAction: @selector(delete:)];
3051  [rename setTarget: [MailboxManagerController singleInstance]];
3052  [rename setAction: @selector(rename:)];
3053#endif
3054
3055  // Sync with the user's defaults
3056  [[NSUserDefaults standardUserDefaults] synchronize];
3057
3058  // We create our console
3059  [ConsoleWindowController singleInstance];
3060
3061  // We load all our bundles
3062  [self _loadBundles];
3063
3064  // We start our task manager and our global timer
3065  [[TaskManager singleInstance] run];
3066
3067  //
3068  // We show of MailboxManager window, if we need to.
3069  // Under GNUstep, we MUST do this _before_ showing any MailWindow:s.
3070  //
3071#ifndef MACOSX
3072  if ([[NSUserDefaults standardUserDefaults] boolForKey: @"OPEN_MAILBOXMANAGER_ON_STARTUP"])
3073    {
3074      [self showMailboxManager: nil];
3075    }
3076#endif
3077
3078  // We show the Console window, if we need to.
3079  if ([[NSUserDefaults standardUserDefaults] boolForKey: @"OPEN_CONSOLE_ON_STARTUP"])
3080    {
3081      [self showConsoleWindow: nil];
3082    }
3083
3084  [Utilities restoreOpenFoldersForStore: aLocalStore];
3085  [self _connectToIMAPServers];
3086
3087  // If we must show the Preferences window, we show it right now. That happens if for example,
3088  // we started GNUMail for the first time and the user has chosen to configure it.
3089  if (mustShowPreferencesWindow)
3090    {
3091      [self showPreferencesWindow: nil];
3092    }
3093
3094  // We register our service
3095  [NSApp setServicesProvider: self];
3096
3097  // We set up our initial list of incoming mail servers
3098  [self _updateGetNewMailMenuItems: nil];
3099
3100  // We set up our initial list of filters for the menu
3101  [self _updateFilterMenuItems: nil];
3102
3103  // We load all the items for the supported encodings (in Pantomime) in the encoding menu
3104  [self _updateTextEncodingsMenu: self];
3105
3106  [self _updateVisibleColumns];
3107
3108  [[MailboxManagerController singleInstance] restoreUnsentMessages];
3109
3110  // We finally check for new mails on startup, if we need to.
3111#warning FIXME move once we are done initializing any specific IMAP store and do it right away for POP3 accounts
3112  [[TaskManager singleInstance] checkForNewMail: self  controller: nil];
3113
3114  // We are done initing
3115  doneInit = YES;
3116
3117  // If a window has requested to be on top, do it now.
3118  if (requestLastMailWindowOnTop != nil)
3119    {
3120      [requestLastMailWindowOnTop makeKeyAndOrderFront: self];
3121      [GNUMail setLastMailWindowOnTop: requestLastMailWindowOnTop];
3122      requestLastMailWindowOnTop = nil;
3123    }
3124
3125}
3126
3127
3128//
3129// methods invoked by notifications
3130//
3131- (void) selectionInTextViewHasChanged: (id) sender
3132{
3133  if ([[sender object] selectedRange].length)
3134    {
3135      [enterSelection setAction: @selector(enterSelectionInFindPanel:)];
3136    }
3137  else
3138    {
3139      [enterSelection setAction: NULL];
3140    }
3141}
3142
3143
3144//
3145// access / mutation methods
3146//
3147+ (NSArray *) allBundles
3148{
3149  return allBundles;
3150}
3151
3152
3153+ (NSArray *) allMailWindows
3154{
3155  return allMailWindows;
3156}
3157
3158
3159+ (NSString *) currentWorkingPath
3160{
3161  return currentWorkingPath;
3162}
3163
3164
3165+ (void) setCurrentWorkingPath: (NSString *) thePath
3166{
3167  ASSIGN(currentWorkingPath, thePath);
3168}
3169
3170
3171+ (id) lastAddressTakerWindowOnTop
3172{
3173  return lastAddressTakerWindowOnTop;
3174}
3175
3176
3177+ (void) setLastAddressTakerWindowOnTop: (id) aWindow
3178{
3179  lastAddressTakerWindowOnTop = aWindow;
3180}
3181
3182
3183+ (id) lastMailWindowOnTop
3184{
3185  return lastMailWindowOnTop;
3186}
3187
3188
3189//
3190//
3191//
3192+ (void) setLastMailWindowOnTop: (id) aWindow
3193{
3194  lastMailWindowOnTop = aWindow;
3195}
3196
3197//
3198//
3199//
3200- (NSMenu *) saveMenu
3201{
3202  return save;
3203}
3204
3205//
3206// other methods
3207//
3208- (void) addItemToMenuFromTextAttachment: (NSTextAttachment *) theTextAttachment
3209{
3210  NSFileWrapper *aFileWrapper;
3211  ExtendedMenuItem *menuItem;
3212
3213  aFileWrapper = [theTextAttachment fileWrapper];
3214
3215  menuItem = [[ExtendedMenuItem alloc] initWithTitle: [aFileWrapper preferredFilename]
3216				       action: @selector(saveAttachment:)
3217				       keyEquivalent: @""];
3218  [menuItem setTextAttachment: theTextAttachment];
3219  [save addItem: menuItem];
3220  RELEASE(menuItem);
3221}
3222
3223
3224//
3225//
3226//
3227+ (void) addEditWindow: (id) theEditWindow
3228{
3229  if (allEditWindows && theEditWindow )
3230    {
3231      [allEditWindows addObject: theEditWindow];
3232    }
3233}
3234
3235
3236//
3237//
3238//
3239+ (void) addMailWindow: (id) theMailWindow
3240{
3241  if (theMailWindow)
3242    {
3243      [allMailWindows addObject: theMailWindow];
3244    }
3245}
3246
3247//
3248// Used on OS X for AppleScript support. It is also used
3249// in the newMessageWithRecipient: userData: error: method
3250// defined in GNUMail+Services.
3251//
3252- (void) newMessageWithRecipient: (NSString *) aString
3253{
3254  CWInternetAddress *anInternetAddress;
3255  EditWindowController *aController;
3256  CWMessage *aMessage;
3257
3258  // We create a new message and we set the recipient
3259  [aString retain];
3260  aMessage = [[CWMessage alloc] init];
3261  anInternetAddress = [[CWInternetAddress alloc] initWithString: aString];
3262  [aString retain];
3263  [anInternetAddress setType: PantomimeToRecipient];
3264  [aMessage addRecipient: anInternetAddress];
3265  RELEASE(anInternetAddress);
3266
3267  // We create our controller and we show the window
3268  aController = [[EditWindowController alloc] initWithWindowNibName: @"EditWindow"];
3269  [allEditWindowControllers addObject:aController];
3270
3271  if (aController)
3272    {
3273      [[aController window] setTitle: _(@"New message...")];
3274      [aController setMessage: aMessage];
3275      [aController setShowCc: NO];
3276      [aController setAccountName: nil];
3277
3278      // If we just got launched, as to to be put on top after we are done initing
3279      if (!doneInit)
3280	{
3281	  requestLastMailWindowOnTop = [aController window];
3282	}
3283      else
3284	{
3285	  [[aController window] makeKeyAndOrderFront: self];
3286	}
3287    }
3288
3289  RELEASE(aMessage);
3290}
3291
3292
3293//
3294//
3295//
3296+ (void) removeEditWindow: (id) theEditWindow
3297{
3298  if (allEditWindows && theEditWindow )
3299    {
3300      unsigned i;
3301
3302      for (i = 0; i < [allEditWindowControllers count]; i++)
3303        {
3304          if ([[allEditWindowControllers objectAtIndex: i] window] == theEditWindow)
3305            [allEditWindowControllers removeObjectAtIndex: i];
3306        }
3307      [allEditWindows removeObject: theEditWindow];
3308    }
3309}
3310
3311
3312//
3313//
3314//
3315+ (void) removeMailWindow: (id) theMailWindow
3316{
3317  if (theMailWindow)
3318    {
3319      unsigned i;
3320
3321      for (i = 0; i < [allMailWindowControllers count]; i++)
3322        {
3323          if ([[allMailWindowControllers objectAtIndex: i] window] == theMailWindow)
3324            [allMailWindowControllers removeObjectAtIndex: i];
3325        }
3326      [allMailWindows removeObject: theMailWindow];
3327    }
3328}
3329
3330@end
3331
3332//
3333// Scripting support; still experimental code.
3334//
3335#ifdef MACOSX
3336@implementation GNUMail (KeyValueCoding)
3337
3338- (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key
3339{
3340  return [key isEqualToString:@"messageCompositions"];
3341}
3342
3343// accessors for to-many relationships:
3344-(NSMutableArray*)messageCompositions
3345{
3346  return _messageCompositions;
3347}
3348
3349-(void)setMessageCompositions: (NSMutableArray*)messageCompositions
3350{
3351  [_messageCompositions setArray: messageCompositions];
3352}
3353
3354
3355//
3356// Accessors for to-many relationships (See NSScriptKeyValueCoding.h)
3357//
3358- (void) addInMessageCompositions: (MessageComposition *) object
3359{
3360  [self insertInMessageCompositions: object atIndex: [_messageCompositions count]];
3361}
3362
3363- (void) insertInMessageCompositions: (MessageComposition *) object
3364{
3365  [self insertInMessageCompositions: object atIndex: [_messageCompositions count]];
3366}
3367
3368- (void) insertInMessageCompositions: (MessageComposition *) object atIndex: (unsigned) index
3369{
3370  [_messageCompositions insertObject: object atIndex: index];
3371
3372}
3373
3374- (void) replaceInMessageCompositions: (MessageComposition *) object atIndex: (unsigned) index
3375{
3376  [_messageCompositions replaceObjectAtIndex: index withObject: object];
3377}
3378
3379- (void) removeFromMessageCompositionsAtIndex: (unsigned) index
3380{
3381  [_messageCompositions removeObjectAtIndex: index];
3382}
3383
3384- (id) valueInMessageCompositionsAtIndex: (unsigned) index
3385{
3386  return ([_messageCompositions objectAtIndex: index]);
3387}
3388
3389@end
3390#endif
3391
3392
3393//
3394// Private methods
3395//
3396@implementation GNUMail (Private)
3397
3398//
3399// Tries to load the property page. Returns NO in case of a failure
3400// or if there's no update available.
3401//
3402- (BOOL) _checkForUpdate
3403{
3404  BOOL checked;
3405
3406  checked = NO;
3407
3408  NS_DURING
3409    {
3410      NSString *aString;
3411      NSData *aData;
3412      NSURL *aURL;
3413
3414      aURL = [NSURL URLWithString: PROPERTY_URL];
3415
3416      // Fetch the property list from PROPERTY_URL
3417      aData = [aURL resourceDataUsingCache: NO];
3418
3419      // Decode the property list
3420      aString = [[NSString alloc] initWithData: aData
3421				   encoding: NSUTF8StringEncoding];
3422
3423      // Check the content
3424      checked = [self _checkDictionary: [aString propertyList]];
3425      RELEASE(aString);
3426    }
3427  NS_HANDLER
3428    {
3429      // Something went wrong, eg. page unavailable
3430      [localException raise];
3431      checked = NO;
3432    }
3433  NS_ENDHANDLER
3434
3435  return checked;
3436}
3437
3438
3439//
3440// Retrieves the current (running application) and the latest
3441// (from the web) version numbers
3442//
3443- (BOOL) _checkDictionary: (NSDictionary *) theDictionary
3444{
3445  NSString *latestVersion;
3446  NSComparisonResult result;
3447
3448  //
3449  // If dictionary is empty, raise an exception and return
3450  //
3451  if (!theDictionary)
3452    {
3453      [NSException raise: @"UpdateException"
3454                  format: @"%@",
3455                   _(@"Unable to retrieve software information.")];
3456      return NO;
3457    }
3458
3459  //
3460  // Get the latest version number as posted on "the net"
3461  //
3462  latestVersion = [theDictionary objectForKey: [[NSProcessInfo processInfo] processName]];
3463
3464  //
3465  // Now compare them
3466  //
3467  result = CompareVersion(GNUMailVersion(), latestVersion);
3468
3469  if (result == NSOrderedDescending || result == NSOrderedSame)
3470    {
3471      return NO;
3472    }
3473
3474  //
3475  // Cool, a new version...
3476  //
3477  [self _newVersionAvailable: latestVersion];
3478
3479  return YES;
3480}
3481
3482
3483//
3484//
3485//
3486- (void) _connectToIMAPServers
3487{
3488  NSDictionary *allAccounts, *allValues;
3489  NSArray *allKeys;
3490  NSUInteger i;
3491
3492  allAccounts = [Utilities allEnabledAccounts];
3493  allKeys = [allAccounts allKeys];
3494
3495  for (i = 0; i < [allKeys count]; i++)
3496    {
3497      allValues = [[allAccounts objectForKey: [allKeys objectAtIndex: i]] objectForKey: @"RECEIVE"];
3498
3499      if ([[allValues objectForKey: @"SERVERTYPE"] intValue] == IMAP)
3500	{
3501	  CWURLName *theURLName;
3502
3503	  theURLName = [[CWURLName alloc] initWithString: [NSString stringWithFormat: @"imap://%@@%@/",
3504								    [allValues objectForKey: @"USERNAME"],
3505								    [allValues objectForKey: @"SERVERNAME"]]];
3506
3507	  [[MailboxManagerController singleInstance] storeForURLName: theURLName];
3508	  RELEASE(theURLName);
3509	}
3510    }
3511}
3512
3513
3514//
3515// Method used to load all bundles in all domains.
3516// FIXME: Offer a way to the user to specify a list of bundles
3517//        that he/she DOES NOT want to load automatically.
3518//
3519- (void) _loadBundles
3520{
3521  NSFileManager *aFileManager;
3522  NSMutableArray *allPaths;
3523  NSArray *allFiles;
3524  NSString *aPath;
3525  NSUInteger i, j;
3526
3527  aFileManager = [NSFileManager defaultManager];
3528
3529  allPaths =  [[NSMutableArray alloc] initWithArray: NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
3530											 NSLocalDomainMask|
3531											 NSNetworkDomainMask|
3532											 NSSystemDomainMask|
3533											 NSUserDomainMask,
3534											 YES)];
3535
3536  for (i = 0; i < [allPaths count]; i++)
3537    {
3538      // We remove any potential duplicate paths in our allPaths array.
3539      [allPaths removeObject: [allPaths objectAtIndex: i] inRange: NSMakeRange(i+1, [allPaths count]-i-1)];
3540
3541      aPath = [NSString stringWithFormat: @"%@/GNUMail", [allPaths objectAtIndex: i]];
3542      allFiles = [aFileManager directoryContentsAtPath: aPath];
3543
3544      for (j = 0; j < [allFiles count]; j++)
3545	{
3546	  NSString *aString;
3547
3548	  aString = [allFiles objectAtIndex: j];
3549
3550	  // If we found a bundle, let's load it!
3551	  if ([[aString pathExtension] isEqualToString: @"bundle"])
3552	    {
3553	      id<GNUMailBundle> aModule;
3554	      NSBundle *aBundle;
3555	      NSString *path;
3556
3557	      path = [NSString stringWithFormat: @"%@/%@",
3558			       aPath,
3559			       aString];
3560
3561	      aBundle = [NSBundle bundleWithPath: path];
3562
3563	      if (aBundle)
3564		{
3565		  Class aClass;
3566
3567		  aClass = [aBundle principalClass];
3568
3569		  // We ensure our bundle is really a GNUMail bundle.
3570		  if (![aClass conformsToProtocol: @protocol(GNUMailBundle)])
3571		    {
3572		      continue;
3573		    }
3574
3575		  aModule = [aClass singleInstance];
3576
3577		  if (aModule)
3578		    {
3579		      [aModule setOwner: self];
3580		      [allBundles addObject: aModule];
3581		      ADD_CONSOLE_MESSAGE(_(@"Loaded bundle at path %@"), path);
3582		    }
3583		  else
3584		    {
3585		      ADD_CONSOLE_MESSAGE((@"Failed to initialize bundle at path %@"), path);
3586		    }
3587		}
3588	      else
3589		{
3590		  ADD_CONSOLE_MESSAGE(_(@"Error loading bundle at path %@"), path);
3591		}
3592	    }
3593	}
3594    }
3595
3596  RELEASE(allPaths);
3597}
3598
3599
3600//
3601//
3602//
3603- (void) _makeFilter: (int) theSource
3604{
3605  id aFilteringModule, aWindowController;
3606  FilterCriteria *aCriteria;
3607  CWMessage *theMessage;
3608  NSString *aString;
3609  Filter *aFilter;
3610  NSRange aRange;
3611  int index;
3612
3613  aWindowController = [[GNUMail lastMailWindowOnTop] delegate];
3614  theMessage = [aWindowController selectedMessage];
3615
3616  aCriteria = AUTORELEASE([[FilterCriteria alloc] init]);
3617  aFilter = AUTORELEASE([[Filter alloc] init]);
3618
3619#warning add support for merging one to three messages into one rule
3620
3621  switch (theSource)
3622    {
3623    case EXPERT:
3624      aString = [[theMessage allHeaders] objectForKey: @"List-Id"];
3625
3626      if (!aString)
3627	{
3628	  NSBeep();
3629	  return;
3630	}
3631
3632      aRange = [aString rangeOfString: @"<"  options: NSBackwardsSearch];
3633
3634      if (aRange.length)
3635	{
3636	  aString = [aString substringWithRange: NSMakeRange(aRange.location+1,[aString length]-aRange.location-2)];
3637	}
3638      else
3639	{
3640	  NSBeep();
3641	  return;
3642	}
3643
3644      [aCriteria setCriteriaString: aString];
3645      [aCriteria setCriteriaSource: EXPERT];
3646      [aCriteria setCriteriaHeaders: [NSArray arrayWithObject: @"List-Id"]];
3647      [aFilter setDescription: [NSString stringWithFormat: _(@"%@ mailing list"), aString]];
3648      break;
3649
3650    case FROM:
3651      [aCriteria setCriteriaString: [[theMessage from] address]];
3652      [aCriteria setCriteriaSource: FROM];
3653      [aFilter setDescription: [[theMessage from] personal]];
3654      break;
3655
3656    case TO:
3657      {
3658        NSArray *recps;
3659        CWInternetAddress *ia;
3660        NSUInteger i;
3661
3662        recps = [theMessage recipients];
3663        i = 0;
3664        ia = nil;
3665        while (i < [recps count] && [ia type] != PantomimeToRecipient)
3666          ia = [recps objectAtIndex:i++];
3667        if (ia)
3668          {
3669            NSString *desc;
3670
3671            [aCriteria setCriteriaString: [ia address]];
3672            [aCriteria setCriteriaSource: TO];
3673            desc = [ia personal];
3674            if (!desc)
3675              desc = [ia address];
3676            [aFilter setDescription: desc];
3677          }
3678      }
3679      break;
3680
3681    case CC:
3682      {
3683        NSArray *recps;
3684        CWInternetAddress *ia;
3685        NSUInteger i;
3686
3687        recps = [theMessage recipients];
3688        i = 0;
3689        ia = nil;
3690        while (i < [recps count] && [ia type] != PantomimeCcRecipient)
3691          ia = [recps objectAtIndex:i++];
3692        if (ia)
3693          {
3694            NSString *desc;
3695
3696            [aCriteria setCriteriaString: [ia address]];
3697            [aCriteria setCriteriaSource: CC];
3698            desc = [ia personal];
3699            if (!desc)
3700              desc = [ia address];
3701            [aFilter setDescription: desc];
3702          }
3703      }
3704      break;
3705
3706    case SUBJECT:
3707    default:
3708      [aCriteria setCriteriaString: [theMessage subject]];
3709      [aCriteria setCriteriaSource: SUBJECT];
3710      [aFilter setDescription: [theMessage subject]];
3711    }
3712
3713  [aCriteria setCriteriaCondition: AND];
3714  [aFilter setCriterias: [NSArray arrayWithObjects: aCriteria,
3715				  AUTORELEASE([[FilterCriteria alloc] init]),
3716				  AUTORELEASE([[FilterCriteria alloc] init]), nil]];
3717
3718  [[FilterManager singleInstance] addFilter: aFilter];
3719
3720  aFilteringModule = [NSBundle instanceForBundleWithName: @"Filtering"];
3721  index = [[[FilterManager singleInstance] filters] count]-1;
3722
3723  if ([[aFilteringModule performSelector: @selector(editFilter:)
3724			 withObject: [NSNumber numberWithInt: index]] intValue] == NSRunAbortedResponse)
3725    {
3726      [[FilterManager singleInstance] removeFilter: aFilter];
3727      [aFilteringModule performSelector: @selector(updateView)];
3728    }
3729}
3730
3731
3732//
3733// Opens the 'new version available' dialog and offers to
3734// download if possible (read: on Mac OS X)
3735//
3736- (void) _newVersionAvailable: (NSString *) theVersion
3737{
3738  NSString *aURL;         // The URL where to get it from
3739  NSString *firstButton;  // Default (OK) button
3740  NSString *secondButton; // Alternate (Cancel) button
3741  NSString *aMessage;     // The message we display to the user.
3742
3743  int result;
3744
3745  aMessage = [NSString stringWithFormat: _(@"The latest version of GNUMail is %@.\n"),
3746		       theVersion];
3747
3748  //
3749  // GNUstep's NSWorkspace doesn't react to -openURL:
3750  // but MACOSX does...
3751  //
3752#ifdef MACOSX
3753  aMessage = [aMessage stringByAppendingString: _(@"Would you like to download the new version now?")];
3754  aURL = DOWNLOAD_URL;
3755  firstButton = _(@"Update now");
3756  secondButton = _(@"Update later");
3757#else
3758  aMessage = [aMessage stringByAppendingFormat: _(@"Check < %@ > for more details."), GNUMailBaseURL()];
3759  aURL = nil;
3760  firstButton = _(@"OK");
3761  secondButton = NULL;
3762#endif
3763
3764  result = NSRunInformationalAlertPanel(_(@"A new version of GNUMail is now available."),
3765					aMessage,
3766					firstButton,
3767					secondButton,
3768					NULL);
3769
3770  if (result == NSAlertDefaultReturn)
3771    {
3772      if (aURL)
3773	{
3774	  [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: aURL]];
3775	}
3776    }
3777}
3778
3779
3780//
3781//
3782//
3783- (void) _removeAllItemsFromMenu: (NSMenu *) theMenu
3784{
3785  int i;
3786
3787  for (i = ([theMenu numberOfItems] - 1); i >= 0; i--)
3788    {
3789      [theMenu removeItemAtIndex: i];
3790    }
3791}
3792
3793
3794//
3795//
3796//
3797- (void) _savePanelDidEnd: (NSSavePanel *) theSheet
3798	       returnCode: (int) returnCode
3799	      contextInfo: (void  *) contextInfo
3800{
3801
3802  NSString *aFilename;
3803  NSData *aData;
3804
3805  aFilename = [theSheet filename];
3806  aData = (NSData *)contextInfo;
3807
3808  // if successful, save file under designated name
3809  if (returnCode == NSAlertDefaultReturn)
3810    {
3811      if (![aData writeToFile: aFilename atomically: YES])
3812        {
3813	  NSBeep();
3814        }
3815      else
3816	{
3817	  [[NSFileManager defaultManager] enforceMode: 0600  atPath: aFilename];
3818	}
3819
3820      [GNUMail setCurrentWorkingPath: [aFilename stringByDeletingLastPathComponent]];
3821    }
3822
3823  RELEASE(aData);
3824}
3825
3826
3827//
3828//
3829//
3830- (void) _updateFilterMenuItems: (id) sender
3831{
3832  BOOL isDir;
3833
3834  if ([[NSFileManager defaultManager] fileExistsAtPath: PathToFilters()
3835				      isDirectory: &isDir] &&
3836      !isDir)
3837    {
3838      FilterManager *aFilterManager;
3839      NSMenuItem *aMenuItem;
3840      int i;
3841
3842      // We first remove all our items in the current menu
3843      [self _removeAllItemsFromMenu: filters];
3844
3845      aFilterManager = [FilterManager singleInstance];
3846
3847      // Our "All" menu item
3848      aMenuItem = [[NSMenuItem alloc] initWithTitle: _(@"All")
3849				      action: @selector(applyManualFilter:)
3850				      keyEquivalent: @""];
3851      [aMenuItem setTag: -1];
3852      [filters addItem: aMenuItem];
3853      RELEASE(aMenuItem);
3854
3855      for (i = 0; i < [[aFilterManager filters] count]; i++)
3856	{
3857	  Filter *aFilter;
3858
3859	  aFilter = [[aFilterManager filters] objectAtIndex: i];
3860
3861	  aMenuItem = [[NSMenuItem alloc] initWithTitle: [aFilter description]
3862					  action: @selector(applyManualFilter:)
3863					  keyEquivalent: @""];
3864	  [aMenuItem setTag: i];
3865	  [filters addItem: aMenuItem];
3866	  RELEASE(aMenuItem);
3867	}
3868    }
3869}
3870
3871
3872//
3873//
3874//
3875- (void) _updateGetNewMailMenuItems: (id) sender
3876{
3877  NSDictionary *allValues;
3878  NSMenuItem *aMenuItem;
3879  NSArray *allKeys;
3880  NSString *aKey;
3881
3882  int i;
3883
3884  // We first remove all our items in the current menu
3885  [self _removeAllItemsFromMenu: incomingMailServers];
3886
3887  // Our "All" menu item
3888  aMenuItem = [[NSMenuItem alloc] initWithTitle: _(@"All")
3889				  action: @selector(getNewMessages:)
3890				  keyEquivalent: @"N"];
3891  [aMenuItem setTarget: self];
3892  [aMenuItem setTag: -1];
3893  [incomingMailServers addItem: aMenuItem];
3894  RELEASE(aMenuItem);
3895
3896  // We sort the array to be sure to keep the order.
3897  allKeys = [[[Utilities allEnabledAccounts] allKeys]
3898	      sortedArrayUsingSelector: @selector(compare:)];
3899
3900  for (i = 0; i < [allKeys count]; i++)
3901    {
3902      aKey = [allKeys objectAtIndex: i];
3903      allValues = [[[[NSUserDefaults standardUserDefaults] objectForKey: @"ACCOUNTS"] objectForKey: aKey]
3904		    objectForKey: @"RECEIVE"];
3905
3906      // We only consider our POP3 and UNIX receiving accounts - both
3907      // being NOT set to never check mails
3908      if ((![allValues objectForKey: @"SERVERTYPE"] ||
3909	   [[allValues objectForKey: @"SERVERTYPE"] intValue] == POP3 ||
3910	   [[allValues objectForKey: @"SERVERTYPE"] intValue] == UNIX) &&
3911	  [[allValues objectForKey: @"RETRIEVEMETHOD"] intValue] != NEVER)
3912	{
3913	  aMenuItem = [[NSMenuItem alloc] initWithTitle: aKey
3914					  action: @selector(getNewMessages:)
3915					  keyEquivalent: @""];
3916	  [aMenuItem setTarget: self];
3917	  [aMenuItem setTag: i];
3918	  [incomingMailServers addItem: aMenuItem];
3919	  RELEASE(aMenuItem);
3920	}
3921    }
3922}
3923
3924
3925//
3926//
3927//
3928- (void) _updateTextEncodingsMenu: (id) sender
3929{
3930  NSMutableArray *aMutableArray;
3931  NSMenuItem *item;
3932  int i;
3933
3934  [self _removeAllItemsFromMenu: textEncodings];
3935
3936  item = [[NSMenuItem alloc] initWithTitle: _(@"Default")
3937			     action: @selector(changeTextEncoding:)
3938			     keyEquivalent: @""];
3939  [item setTag: -1];
3940  [textEncodings addItem: item];
3941  RELEASE(item);
3942
3943  aMutableArray = [[NSMutableArray alloc] init];
3944  [aMutableArray addObjectsFromArray: [[CWCharset allCharsets] allValues]];
3945  [aMutableArray sortUsingSelector: @selector(compare:)];
3946
3947  for (i = 0; i < [aMutableArray count]; i++)
3948    {
3949      item = [[NSMenuItem alloc] initWithTitle: [aMutableArray objectAtIndex: i]
3950				 action: @selector(changeTextEncoding:)
3951				 keyEquivalent: @""];
3952      [item setTag: i];
3953      [textEncodings addItem: item];
3954      RELEASE(item);
3955    }
3956
3957  RELEASE(aMutableArray);
3958}
3959
3960
3961//
3962//
3963//
3964- (void) _updateVisibleColumns
3965{
3966  NSArray *theColumns;
3967  int i;
3968
3969  theColumns = [[NSUserDefaults standardUserDefaults] objectForKey: @"SHOWNTABLECOLUMNS"];
3970
3971  if (theColumns)
3972    {
3973      for (i = 0; i < [theColumns count]; i++)
3974	{
3975	  NSString *column;
3976
3977	  column = [theColumns objectAtIndex: i];
3978
3979	  if ([column isEqualToString: @"Date"])
3980	    {
3981	      [[columns itemWithTag: GNUMailDateColumn] setState: NSOnState];
3982	    }
3983	  else if ([column isEqualToString: @"Flagged"])
3984	    {
3985	      [[columns itemWithTag: GNUMailFlagsColumn] setState: NSOnState];
3986	    }
3987	  else if ([column isEqualToString: @"From"])
3988	    {
3989	      [[columns itemWithTag: GNUMailFromColumn] setState: NSOnState];
3990	    }
3991	  else if ([column isEqualToString: @"Number"] )
3992	    {
3993	      [[columns itemWithTag: GNUMailNumberColumn] setState: NSOnState];
3994	    }
3995	  else if ([column isEqualToString: @"Size"])
3996	    {
3997	      [[columns itemWithTag: GNUMailSizeColumn] setState: NSOnState];
3998	    }
3999	  else if ([column isEqualToString: @"Status"])
4000	    {
4001	      [[columns itemWithTag: GNUMailStatusColumn] setState: NSOnState];
4002	    }
4003	  else if ([column isEqualToString: @"Subject"])
4004	    {
4005	      [[columns itemWithTag: GNUMailSubjectColumn] setState: NSOnState];
4006	    }
4007
4008
4009	}
4010    }
4011  else
4012    {
4013      for (i = 0; i < [columns numberOfItems]; i++)
4014	{
4015	  [[columns itemAtIndex: i] setState: NSOnState];
4016	}
4017    }
4018}
4019
4020@end
4021