1/* 2** MessageComposition.m 3** 4** Copyright (c) 2001, 2002, 2003 Ujwal S. Sathyam 5** 6** Author: Ujwal S. Sathyam 7** 8** Description: Scriptable class that works with an EditWindowController 9** and a Message. 10** 11** This program is free software; you can redistribute it and/or modify 12** it under the terms of the GNU General Public License as published by 13** the Free Software Foundation; either version 2 of the License, or 14** (at your option) any later version. 15** 16** This program is distributed in the hope that it will be useful, 17** but WITHOUT ANY WARRANTY; without even the implied warranty of 18** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19** GNU General Public License for more details. 20** 21** You should have received a copy of the GNU General Public License 22** along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "MessageComposition.h" 26#include "Constants.h" 27#include "GNUMail.h" 28#include "EditWindowController.h" 29#include "ExtendedTextView.h" 30#include "Utilities.h" 31 32#include <Pantomime/CWConstants.h> 33#include <Pantomime/CWInternetAddress.h> 34#include <Pantomime/CWMessage.h> 35 36NSString *NSOperationNotSupportedForKeyException = @"NSOperationNotSupportedForKeyException"; 37 38// 39// 40// 41@implementation MessageComposition 42 43- (id) init 44{ 45 self = [super init]; 46 47 if (self != nil) 48 { 49 _recipients = [[NSMutableArray allocWithZone:[self zone]] init]; 50 _attachments = [[NSMutableArray allocWithZone:[self zone]] init]; 51 } 52 53 // NSLog(@"Initialized message 0x%x", self); 54 return self; 55} 56 57 58// 59// 60// 61- (void) dealloc 62{ 63 [[NSNotificationCenter defaultCenter] removeObserver:self]; 64 [_author release]; 65 [_content release]; 66 [_subject release]; 67 [_recipients release]; 68 [_attachments release]; 69 [_account release]; 70 71 [super dealloc]; 72} 73 74 75// 76// 77// 78- (NSArray *) recipientsWithClass: (Class) theClass 79{ 80 NSArray *recipients = [self recipients]; 81 NSMutableArray *result = [NSMutableArray array]; 82 unsigned i, c = [recipients count]; 83 id curRecipient; 84 85 for (i=0; i<c; i++) 86 { 87 curRecipient = [recipients objectAtIndex:i]; 88 if ([curRecipient isKindOfClass:theClass]) 89 { 90 [result addObject:curRecipient]; 91 } 92 } 93 return result; 94} 95 96 97// 98// 99// 100- (void) send 101{ 102 // NSLog(@"Sending message composition 0x%x", self); 103 104 [self _loadMessage]; 105 // Send the message! 106 [_editWindowController sendMessage: nil]; 107} 108 109 110// 111// 112// 113- (void) addAttachment: (NSString *) aFileName 114{ 115 if (aFileName) 116 { 117 NSString *theFile = [aFileName copy]; 118 [_attachments addObject: theFile]; 119 RELEASE(theFile); 120 } 121} 122 123 124// 125// accessors for attributes: 126// 127- (NSString *) author 128{ 129 return _author; 130} 131 132 133// 134// 135// 136- (void) setAuthor: (NSString *) author 137{ 138 if ( ![author isEqual: _author] ) 139 { 140 NSString *temp = [author copy]; 141 [_author release]; 142 _author = temp; 143 } 144} 145 146 147// 148// 149/// 150- (NSTextStorage *) content 151{ 152 return _content; 153} 154 155 156// 157// 158// 159- (void) setContent: (NSTextStorage *) content 160{ 161 if ( ![content isEqual: _content] ) 162 { 163 NSTextStorage *temp = [content copy]; 164 [_content release]; 165 _content = temp; 166 } 167} 168 169 170// 171// 172// 173- (int) signaturePosition 174{ 175 return _signaturePosition; 176} 177 178 179// 180// 181// 182- (void) setSignaturePosition: (int) signaturePosition 183{ 184 if ( signaturePosition != _signaturePosition ) 185 { 186 _signaturePosition = signaturePosition; 187 } 188} 189 190 191// 192// 193// 194- (BOOL) hasSignature 195{ 196 return _hasSignature; 197} 198 199 200// 201// 202// 203- (void) setHasSignature: (BOOL) hasSignature 204{ 205 if ( hasSignature != _hasSignature ) 206 { 207 _hasSignature = hasSignature; 208 } 209} 210 211 212// 213// 214// 215- (NSString*) subject 216{ 217 return _subject; 218} 219 220 221// 222// 223// 224-(void) setSubject: (NSString *) subject 225{ 226 if ( ![subject isEqual: _subject] ) 227 { 228 NSString *temp = [subject copy]; 229 [_subject release]; 230 _subject = temp; 231 } 232} 233 234 235// 236// 237// 238- (void) show: (BOOL) flag 239{ 240 if (flag) 241 { 242 [self _loadMessage]; 243 [[_editWindowController window] makeKeyAndOrderFront: nil]; 244 } 245 else 246 { 247 [[_editWindowController window] close]; 248 } 249} 250 251 252// 253// 254// 255- (NSArray *) attachments 256{ 257 return (_attachments); 258} 259 260 261// 262// 263// 264- (void) setAttachments: (NSArray *) attachments 265{ 266 // We won't allow wholesale setting of these subset keys. 267 [NSException raise: NSOperationNotSupportedForKeyException format: @"Setting 'attachments' key is not supported."]; 268} 269 270 271// 272// 273// 274- (NSString *) account 275{ 276 if (_account != nil) 277 { 278 return (_account); 279 } 280 281 // grab the default account 282 return ([Utilities defaultAccountName]); 283} 284 285 286// 287// 288// 289- (void) setAccount: (NSString *) accountName 290{ 291 if (_account != nil) 292 { 293 RELEASE(_account); 294 _account = nil; 295 } 296 if (accountName != nil) 297 { 298 RETAIN(accountName); 299 _account = accountName; 300 } 301} 302 303 304// 305// accessors for to-many relationships: 306// 307- (NSArray *) recipients 308{ 309 return _recipients; 310} 311 312 313// 314// 315// 316- (void) setRecipients: (NSArray *) recipients 317{ 318 // NSLog(@"MessageComposition: setRecipients"); 319 [_recipients setArray: recipients]; 320} 321 322 323// 324// 325// 326- (NSArray *) ccRecipients 327{ 328 return [self recipientsWithClass: [CcRecipient class]]; 329} 330 331 332// 333// 334// 335- (void) setCcRecipients: (NSArray *) ccRecipients 336{ 337 // We won't allow wholesale setting of these subset keys. 338 [NSException raise: NSOperationNotSupportedForKeyException format: @"Setting 'cc recipients' key is not supported."]; 339} 340 341 342// 343// 344// 345- (NSArray *) bccRecipients 346{ 347 return [self recipientsWithClass: [BccRecipient class]]; 348} 349 350 351// 352// 353// 354- (void) setBccRecipients: (NSArray *) bccRecipients 355{ 356 // We won't allow wholesale setting of these subset keys. 357 [NSException raise: NSOperationNotSupportedForKeyException format: @"Setting 'bcc recipients' key is not supported."]; 358} 359 360 361// 362// 363// 364- (NSArray *) toRecipients 365{ 366 return [self recipientsWithClass: [ToRecipient class]]; 367} 368 369 370// 371// 372// 373- (void) setToRecipients: (NSArray *) toRecipients 374{ 375 // We won't allow wholesale setting of these subset keys. 376 [NSException raise: NSOperationNotSupportedForKeyException format: @"Setting 'to recipients' key is not supported."]; 377} 378 379@end 380 381 382// 383// 384// 385@implementation MessageComposition (KeyValueCoding) 386 387- (id) valueInRecipientsAtIndex: (unsigned) index 388{ 389 // NSLog(@"MessageComposition: valueInRecipientsAtIndex %d", index); 390 return ([[self recipients] objectAtIndex: index]); 391} 392 393 394// 395// 396// 397- (void) replaceInRecipients: (CWInternetAddress *) object 398 atIndex: (unsigned) index 399{ 400 [self removeFromRecipientsAtIndex:index]; 401 [self insertInRecipients:object atIndex:index]; 402} 403 404 405// 406// 407// 408- (void) insertInRecipients: (CWInternetAddress *) object 409{ 410 // NSLog(@"MessageComposition: insertInRecipients 0x%x", object); 411 if ([object type] == 0) 412 { 413 [object setType: PantomimeToRecipient]; 414 } 415 416 [self insertInRecipients: object atIndex: [[self recipients] count]]; 417} 418 419 420// 421// 422// 423- (void) insertInRecipients: (CWInternetAddress *) object 424 atIndex: (unsigned) index 425{ 426 // NSLog(@"MessageComposition: insertInRecipients %@ atIndex %d", [object description], index); 427 [_recipients insertObject:object atIndex:index]; 428 [object setContainer: self]; 429} 430 431 432// 433// 434// 435- (void) removeFromRecipientsAtIndex: (unsigned) index 436{ 437 // NSLog(@"MessageComposition: removeFromRecipientsAtIndex %d", index); 438 [_recipients removeObjectAtIndex:index]; 439} 440 441 442// 443// 444// 445- (id) valueInCcRecipientsAtIndex: (unsigned) index 446{ 447 return ([[self ccRecipients] objectAtIndex: index]); 448} 449 450 451// 452// 453// 454- (void) replaceInCcRecipients: (CcRecipient *) object 455 atIndex: (unsigned) index 456{ 457 NSArray *ccRcpts = [self ccRecipients]; 458 NSArray *recipients = [self recipients]; 459 int newIndex = [recipients indexOfObjectIdenticalTo: [ccRcpts objectAtIndex:index]]; 460 461 if (newIndex != NSNotFound) 462 { 463 [self removeFromRecipientsAtIndex: newIndex]; 464 [self insertInRecipients:object atIndex: newIndex]; 465 } 466 else 467 { 468 // Shouldn't happen. 469 [NSException raise: NSRangeException format: @"Could not find the given 'cc recipient' in the recipients."]; 470 } 471} 472 473 474// 475// 476// 477- (void) insertInCcRecipients: (CcRecipient *) object 478{ 479 [self insertInCcRecipients: object atIndex: [[self ccRecipients] count]]; 480} 481 482 483// 484// 485// 486- (void) insertInCcRecipients: (CcRecipient *) object 487 atIndex: (unsigned) index 488{ 489 NSArray *ccRcpts = [self ccRecipients]; 490 491 if (index == [ccRcpts count]) 492 { 493 [self insertInRecipients:object atIndex: index]; 494 } 495 else 496 { 497 NSArray *recipients = [self recipients]; 498 int newIndex = [recipients indexOfObjectIdenticalTo: [ccRcpts objectAtIndex: index]]; 499 if (newIndex != NSNotFound) 500 { 501 [self insertInRecipients:object atIndex: newIndex]; 502 } 503 else 504 { 505 // Shouldn't happen. 506 [NSException raise: NSRangeException format: @"Could not find the given 'cc recipients' in the recipients."]; 507 } 508 } 509} 510 511 512// 513// 514// 515- (void) removeFromCcRecipientsAtIndex: (unsigned) index 516{ 517 NSArray *ccRcpts = [self ccRecipients]; 518 NSArray *recipients = [self recipients]; 519 int newIndex = [recipients indexOfObjectIdenticalTo: [ccRcpts objectAtIndex: index]]; 520 521 if (newIndex != NSNotFound) 522 { 523 [self removeFromRecipientsAtIndex: newIndex]; 524 } 525 else 526 { 527 // Shouldn't happen. 528 [NSException raise: NSRangeException format: @"Could not find the given 'cc recipients' in the recipients."]; 529 } 530} 531 532 533// 534// 535// 536- (id) valueInBccRecipientsAtIndex: (unsigned) index 537{ 538 return ([[self bccRecipients] objectAtIndex: index]); 539} 540 541 542// 543// 544// 545- (void) replaceInBccRecipients: (BccRecipient *) object 546 atIndex: (unsigned) index 547{ 548 NSArray *bccRcpts = [self bccRecipients]; 549 NSArray *recipients = [self recipients]; 550 int newIndex = [recipients indexOfObjectIdenticalTo: [bccRcpts objectAtIndex:index]]; 551 552 if (newIndex != NSNotFound) 553 { 554 [self removeFromRecipientsAtIndex: newIndex]; 555 [self insertInRecipients: object atIndex: newIndex]; 556 } 557 else 558 { 559 // Shouldn't happen. 560 [NSException raise: NSRangeException format: @"Could not find the given 'bcc recipient' in the recipients."]; 561 } 562} 563 564 565// 566// 567// 568- (void) insertInBccRecipients: (BccRecipient *) object 569{ 570 [self insertInBccRecipients: object atIndex: [[self bccRecipients] count]]; 571} 572 573 574// 575// 576// 577- (void) insertInBccRecipients: (BccRecipient *) object 578 atIndex: (unsigned) index 579{ 580 // implement your method here: 581 NSArray *bccRcpts = [self bccRecipients]; 582 if (index == [bccRcpts count]) 583 { 584 [self insertInRecipients:object atIndex: index]; 585 } 586 else 587 { 588 NSArray *recipients = [self recipients]; 589 int newIndex = [recipients indexOfObjectIdenticalTo: [bccRcpts objectAtIndex: index]]; 590 if (newIndex != NSNotFound) 591 { 592 [self insertInRecipients: object atIndex: newIndex]; 593 } 594 else 595 { 596 // Shouldn't happen. 597 [NSException raise: NSRangeException format: @"Could not find the given 'bcc recipients' in the recipients."]; 598 } 599 } 600} 601 602 603// 604// 605// 606- (void) removeFromBccRecipientsAtIndex: (unsigned) index 607{ 608 NSArray *bccRcpts = [self bccRecipients]; 609 NSArray *recipients = [self recipients]; 610 int newIndex = [recipients indexOfObjectIdenticalTo:[bccRcpts objectAtIndex:index]]; 611 612 if (newIndex != NSNotFound) 613 { 614 [self removeFromRecipientsAtIndex:newIndex]; 615 } 616 else 617 { 618 // Shouldn't happen. 619 [NSException raise:NSRangeException format:@"Could not find the given 'bcc recipients' in the recipients."]; 620 } 621} 622 623 624// 625// 626// 627- (id) valueInToRecipientsAtIndex: (unsigned) index 628{ 629 return ([[self toRecipients] objectAtIndex: index]); 630} 631 632 633// 634// 635// 636- (void) replaceInToRecipients: (ToRecipient *) object 637 atIndex: (unsigned) index 638{ 639 // NSLog(@"MessageComposition: replaceInToRecipients 0x%x at index %d", object, index); 640 NSArray *toRcpts = [self toRecipients]; 641 NSArray *recipients = [self recipients]; 642 int newIndex = [recipients indexOfObjectIdenticalTo:[toRcpts objectAtIndex:index]]; 643 644 if (newIndex != NSNotFound) 645 { 646 [self removeFromRecipientsAtIndex:newIndex]; 647 [self insertInRecipients:object atIndex:newIndex]; 648 } 649 else 650 { 651 // Shouldn't happen. 652 [NSException raise:NSRangeException format:@"Could not find the given 'to recipient' in the recipients."]; 653 } 654} 655 656 657// 658// 659// 660- (void) insertInToRecipients: (ToRecipient *) object 661{ 662 [self insertInToRecipients: object atIndex: [[self toRecipients] count]]; 663} 664 665 666// 667// 668// 669- (void) insertInToRecipients: (ToRecipient *) object 670 atIndex: (unsigned) index 671{ 672 // NSLog(@"MessageComposition: insertInToRecipients 0x%x at index %d", object, index); 673 674 NSArray *toRcpts = [self toRecipients]; 675 if (index == [toRcpts count]) 676 { 677 [self insertInRecipients:object atIndex: index]; 678 } 679 else 680 { 681 NSArray *recipients = [self recipients]; 682 int newIndex = [recipients indexOfObjectIdenticalTo:[toRcpts objectAtIndex:index]]; 683 if (newIndex != NSNotFound) 684 { 685 [self insertInRecipients:object atIndex:newIndex]; 686 } 687 else 688 { 689 // Shouldn't happen. 690 [NSException raise:NSRangeException format:@"Could not find the given 'to recipients' in the recipients."]; 691 } 692 } 693} 694 695 696// 697// 698// 699- (void)removeFromToRecipientsAtIndex: (unsigned) index 700{ 701 NSArray *toRcpts = [self toRecipients]; 702 NSArray *recipients = [self recipients]; 703 int newIndex = [recipients indexOfObjectIdenticalTo:[toRcpts objectAtIndex:index]]; 704 705 if (newIndex != NSNotFound) 706 { 707 [self removeFromRecipientsAtIndex:newIndex]; 708 } 709 else 710 { 711 // Shouldn't happen. 712 [NSException raise:NSRangeException format:@"Could not find the given 'to recipients' in the recipients."]; 713 } 714} 715 716@end 717 718 719// 720// 721// 722@implementation MessageComposition (Private) 723 724- (void) _loadMessage 725{ 726 // NSLog(@"MessageComposer: loading message 0x%x", self); 727 CWInternetAddress *aRecipient; 728 NSEnumerator *anEnumerator; 729 CWMessage *aMessage; 730 NSString *aFileName; 731 732 // We create a new message 733 aMessage = [[CWMessage alloc] init]; 734 735 // We set the recipients 736 anEnumerator = [[self recipients] objectEnumerator]; 737 while ((aRecipient = [anEnumerator nextObject]) != nil) 738 { 739 [aMessage addRecipient: aRecipient]; 740 // NSLog(@"MessageComposition: -send: Added recipient %@", [aRecipient description]); 741 } 742 743 // Set the subject 744 if ([self subject]) 745 { 746 [aMessage setSubject: [self subject]]; 747 // NSLog(@"MessageComposition: -send: Set subject: %@", [self subject]); 748 } 749 750 // Set the content 751 if ([self content]) 752 { 753 [aMessage setContent: [[self content] string]]; 754 // NSLog(@"MessageComposition: -send: Set content: %@", [[self content] string]); 755 } 756 757 // We create our controller, but we do not show the window 758 if (_editWindowController != nil) 759 { 760 [[_editWindowController window] close]; 761 } 762 763 _editWindowController = [[EditWindowController alloc] initWithWindowNibName: @"EditWindow"]; 764 765 if ( _editWindowController ) 766 { 767 [[_editWindowController window] setTitle: _(@"New message...")]; 768 769 // set the source account 770 [_editWindowController setAccountName: [self account]]; 771 772 // Set the message 773 [_editWindowController setMessage: aMessage]; 774 [_editWindowController setShowCc: YES]; 775 [_editWindowController setShowBcc: YES]; 776 777 // Add any attachments 778 anEnumerator = [[self attachments] objectEnumerator]; 779 while ((aFileName = [anEnumerator nextObject]) != nil) 780 { 781 [(ExtendedTextView *)[_editWindowController textView] insertFile: aFileName]; 782 } 783 } 784 785 RELEASE(aMessage); 786} 787 788@end 789 790 791#ifdef MACOSX 792// 793// 794// 795@implementation MessageComposition (ScriptingSupport) 796 797- (NSScriptObjectSpecifier *) objectSpecifier 798{ 799 unsigned index = 0; 800 id classDescription = nil; 801 802 NSScriptObjectSpecifier *containerRef; 803 804 NSArray *messageCompositions = [[NSApp delegate] messageCompositions]; 805 index = [messageCompositions indexOfObjectIdenticalTo:self]; 806 807 if (index != NSNotFound) 808 { 809 containerRef = [NSApp objectSpecifier]; 810 classDescription = [NSClassDescription classDescriptionForClass:[NSApp class]]; 811 //create and return the specifier 812 return [[[NSIndexSpecifier allocWithZone:[self zone]] 813 initWithContainerClassDescription: classDescription 814 containerSpecifier: containerRef 815 key: @"messageCompositions" 816 index: index] autorelease]; 817 } 818 else 819 { 820 return nil; 821 } 822} 823 824 825// 826// Handlers for supported commands: 827// 828- (void) handleSendMessageScriptCommand: (NSScriptCommand *) command 829{ 830 [self send]; 831 return; 832} 833 834 835// 836// 837// 838- (void) handleShowMessageScriptCommand: (NSScriptCommand *) command 839{ 840 [self show: YES]; 841} 842 843 844// 845// 846// 847- (void) handleAttachScriptCommand: (NSScriptCommand *) command 848{ 849 // Get the command's arguments: 850 NSDictionary *args = [command evaluatedArguments]; 851 NSString *file = [args objectForKey:@"file"]; 852 853 [self addAttachment: file]; 854 855 return; 856} 857 858@end 859 860 861// 862// 863// 864@implementation CWInternetAddress (ScriptingSupport) 865 866- (NSScriptObjectSpecifier *) objectSpecifier 867{ 868 unsigned index = 0; 869 id classDescription = nil; 870 871 NSScriptObjectSpecifier *containerRef = nil; 872 873 NSArray *recipients = [[self container] recipients]; 874 index = [recipients indexOfObjectIdenticalTo:self]; 875 876 if (index != NSNotFound) 877 { 878 containerRef = [[self container] objectSpecifier]; 879 classDescription = [containerRef keyClassDescription]; 880 //create and return the specifier 881 return [[[NSIndexSpecifier allocWithZone:[self zone]] 882 initWithContainerClassDescription: classDescription 883 containerSpecifier: containerRef 884 key: @"recipients" 885 index: index] autorelease]; 886 } 887 else 888 { 889 // NSLog(@"recipient not found!"); 890 return nil; 891 } 892} 893 894@end 895 896#endif 897 898