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