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