home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / MailManager / AddressBook.m < prev    next >
Encoding:
Text File  |  1992-05-11  |  10.9 KB  |  374 lines

  1. /*
  2.  * Program:    Distributed Electronic Mail Manager (AddressBook object)
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    8 March 1990
  13.  * Last Edited:    11 May 1992
  14.  *
  15.  * Copyright 1992 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. #import "MailManager.h"
  38.  
  39. @implementation AddressBook
  40.  
  41. // Name of the address book file
  42.  
  43. char *bookfile = "/.addressbook";
  44.  
  45. // Called at initialization to note the entry form
  46.  
  47. - setEntry:anObject
  48. {
  49.   entry = anObject;        // note the entry form
  50.   [entry selectTextAt:0];    // select nickname
  51.   return self;
  52. }
  53.  
  54.  
  55. // Called at initialization to note the personal name
  56.  
  57. - setName:anObject
  58. {
  59.   name = anObject;        // note the personal name
  60.   return self;
  61. }
  62.  
  63.  
  64. // Called at initialization to note the nickname
  65.  
  66. - setNickname:anObject
  67. {
  68.   nickname = anObject;        // note the nickname
  69.   return self;
  70. }
  71.  
  72.  
  73. // Called at initialization to note the net address
  74.  
  75. - setAddress:anObject
  76. {
  77.   address = anObject;        // note the net address
  78.   return self;
  79. }
  80.  
  81.  
  82. // Called at initialization to note the window
  83.  
  84. - setWindow:anObject
  85. {
  86.   window = anObject;        // note the window
  87.   return self;
  88. }
  89.  
  90. // Called at initialization to note the address items
  91.  
  92. - setAddressItems:anObject
  93. {
  94.   NXSize size;
  95.   NXRect frame;
  96.   NXStream *book;
  97.   char tmp[TMPLEN],full[TMPLEN],nick[TMPLEN],adr[TMPLEN];
  98.   char *extra;
  99.   [anObject getFrame:&frame];    // get frame of address items view
  100.                 // create a scroll view
  101.   [(addressItems = [ScrollView newFrame:&frame]) setBorderType:NX_BEZEL];
  102.                 // only vertical scrolling is required
  103.   [addressItems setVertScrollerRequired:T];
  104.                 // allow its size to change
  105.   [addressItems setAutosizing:NX_HEIGHTSIZABLE|NX_WIDTHSIZABLE];
  106.                 // put up the view
  107.   [[anObject superview] replaceSubview:anObject with:addressItems];
  108.                 // get the size minus the scroll bars
  109.   [addressItems getContentSize:&size];
  110.                 // set it as such in the browser frames
  111.   NX_WIDTH (&frame) = size.width = 1300.0; NX_HEIGHT (&frame) = size.height;
  112.                 // create the browser
  113.   browser = [Matrix newFrame:&frame mode:NX_RADIOMODE
  114.          cellClass:[AddressBookCell class] numRows:0 numCols:0];
  115.                 // open address book
  116.   size.height = 13.0;        // small enough to hold the text
  117.   [browser setCellSize:&size];
  118.   size.width = size.height = 0;    // no intercell spacing
  119.   [browser setIntercell:&size];
  120.   [browser setAutoscroll:T];    // make it autoscrolling
  121.   [[browser setAction:@selector(selectAddress:)] setTarget:self];
  122.                 // make address book file name
  123.   strcat (strcpy (tmp,(char *) NXHomeDirectory ()),bookfile);
  124.                 // open the file for read
  125.   if (book = NXMapFile (tmp,NX_READONLY)) {
  126.                 // read and insert address book entries
  127.     while (NXScanf (book,"%[^\t] %[^\t] %[^\t\n]%c",nick,full,adr,tmp) == 4) {
  128.                 // parse extra if any
  129.       if (tmp[0] == '\t') NXScanf (book,"%[^\n] ",(extra = tmp));
  130.       else extra = NIL;        // no extra poop
  131.       [self addNickName:nick fullName:full address:adr extra:extra update:NIL];
  132.     }
  133.                 // flush the stream
  134.     NXCloseMemory (book,NX_FREEBUFFER);
  135.     [browser sizeToCells];    // make the browser big enough to hold them
  136.   }
  137.                 // put the browser in the scroller and display
  138.   [[addressItems setDocView:browser] display];
  139.   [entry selectTextAt:0];    // select nickname
  140.   return self;
  141. }
  142.  
  143. // Put up help panel
  144.  
  145. - help:sender
  146. {
  147.   [NXApp addressHelp:sender];
  148.   return self;
  149. }
  150.  
  151.  
  152. // Return our window
  153.  
  154. - window
  155. {
  156.   return window;
  157. }
  158.  
  159.  
  160. // Initialize all fields
  161.  
  162. - new:sender
  163. {
  164.   [name setStringValue:""];    // zap name
  165.   [nickname setStringValue:""];    // zap nickname
  166.   [address setStringValue:""];    // zap net address
  167.   [entry selectTextAt:0];    // select nickname
  168.   return self;
  169. }
  170.  
  171.  
  172. // User selected an address
  173.  
  174. - selectAddress:sender
  175. {
  176.   id cell = [browser selectedCell];
  177.                 // set all fields in close-up
  178.   [nickname setStringValue:[cell nickName]];
  179.   [name setStringValue:[cell fullName]];
  180.   [address setStringValue:[cell address]];
  181.   [entry selectTextAt:0];    // select nickname
  182.   return self;
  183. }
  184.  
  185. // OK button hit
  186.  
  187. - OK:sender
  188. {
  189.   [self add:NIL];        // do return action, if fail give warning
  190.   return self;
  191. }
  192.  
  193.  
  194. // Return hit in form
  195.  
  196. - add:sender
  197. {
  198.   char *newNickName = (char *) [nickname stringValue];
  199.   char *newFullName = (char *) [name stringValue];
  200.   char *newAddress = (char *) [address stringValue];
  201.                 // must have a nickname
  202.   if (!(newNickName && strlen (newNickName))) [entry selectTextAt:0];
  203.                 // must have a name
  204.   else if (!(newFullName && strlen (newFullName))) [entry selectTextAt:1];
  205.                 // must have an address
  206.   else if (!(newAddress && strlen (newAddress))) [entry selectTextAt:2];
  207.                 // all OK, add it to the book
  208.   else return [self addNickName:newNickName fullName:newFullName
  209.            address:newAddress extra:NIL update:T];
  210.   if (!sender) mm_log ("Missing field in address book entry",ERROR);
  211.   return self;
  212. }
  213.  
  214. // Add new entry or modify existing entry
  215.  
  216. - addNickName:(char *) newNickName fullName:(char *) newFullName
  217.  address:(char *) newAddress extra:(char *) newExtra update:(BOOL) update
  218. {
  219.   id cell;
  220.   char s[TMPLEN],t[TMPLEN],x[TMPLEN];
  221.   int i,m;
  222.                 // make uppercase copies
  223.   ucase (strcpy (s,newNickName));
  224.   ucase (strcpy (t,newFullName));
  225.                 // get size of browser
  226.   [browser getNumRows:&m numCols:&i];
  227.   for (i = 0; i < m; i++)    // search for existing nickname
  228.     if (!strcmp    (s,ucase    // if match
  229.          (strcpy (x,[(cell = [browser cellAt:i :0]) nickName])))) {
  230.                 // create prompting message
  231.       sprintf (x,"Change existing entry for %s?",newNickName);
  232.                 // abort if user rejects
  233.       if (!NXRunAlertPanel ("Change?",x,NIL,"No",NIL)) return self;
  234.                 // remember old extra information
  235.       if ((!newExtra) && [cell extra]) newExtra = strcpy (s,[cell extra]);
  236.                 // else remove the current entry
  237.       [browser removeRowAt:i andFree:T];
  238.       m--;            // one less row in second pass
  239.       break;            // done with this step
  240.     }
  241.   for (i = 0; i < m; i++)    // search for appropriate insertion point
  242.     if (strcmp (t,ucase (strcpy (x,[[browser cellAt:i :0] fullName]))) < 0)
  243.       break;
  244.   [browser insertRowAt:i];    // create a new row
  245.                 // set poop for the new cell
  246.   [[browser cellAt:i :0] setNickName:newNickName fullName:newFullName 
  247.    address:newAddress extra:newExtra];
  248.   return update ? [self update] : self;
  249. }
  250.  
  251.  
  252. // Remove an entry from the address book
  253.  
  254. - remove:sender
  255. {
  256.   int m;
  257.   char *t = (char *) [nickname stringValue];
  258.                 // make sure there is something to search
  259.   if (!(t && strlen (t))) mm_log ("Must specify nickname to remove",ERROR);
  260.   else if ((m = [self find:t]) < 0) mm_log ("Not in the address book",ERROR);
  261.   else [browser removeRowAt:m andFree:T];
  262.   return [self update];
  263. }
  264.  
  265. // Look up address book entry from address block and substitute
  266.  
  267. - lookup:(ADDRESS **) adr
  268. {
  269.   char tmp[TMPLEN];
  270.   id cell;
  271.   char *a,*s;
  272.   ADDRESS *new = NIL;
  273.   char *t = (*adr)->personal;
  274.   ADDRESS *tail = (*adr)->next;
  275.   int i = [self find:(*adr)->mailbox];
  276.                 // substitute host if not in book
  277.   if (i < 0) strcpy ((*adr)->host,domainname);
  278.   else {            // else get address from book
  279.     a = (char *) [(cell = [browser cellAt:i :0]) address];
  280.     rfc822_parse_adrlist (&new,a ? a : "",(char *) domainname);
  281.     if (new) {
  282.       (*adr)->next = NIL;    // yank away tail
  283.       (*adr)->personal = NIL;    // pretty bizarre that someone would do this!!
  284.       mail_free_address (adr);    // no longer need this address
  285.       *adr = new;        // set new address
  286.                 // only if we want to copy the name
  287.       if (!(nopersonal || (*adr)->personal)) {
  288.                 // handle bizarre case
  289.     if (t) (*adr)->personal = t;
  290.     else {            // see if quoted name
  291.       if (((t = (char *) [cell fullName])[0] == '"') &&
  292.           (i = strlen (t) - 1) && (t[i--] == '"'))
  293.         (t = strncpy (tmp,t+1,i))[i] = '\0';
  294.                 // or if in "surname, given" format
  295.       else if (s = strchr (t,',')) {
  296.         i = s - t;        // yes, remember length of surname
  297.         while (*++s == ' ');// ignore whitespace after comma
  298.                 // construct "given surname" format
  299.         t = strncat (strcat (strcpy (tmp,s)," "),t,i);
  300.       }
  301.                 // set personal name
  302.       (*adr)->personal = cpystr (t);
  303.     }
  304.       }
  305.       if (tail) {        // any more addresses?
  306.                 // yes, hunt for tail
  307.     while ((*adr)->next) *adr = (*adr)->next;
  308.     (*adr)->next = tail;    // append remainder of list
  309.       }
  310.     }
  311.     else {            // user put something bogus in the book
  312.       sprintf (tmp,"Unparsable address from address book: %s",a);
  313.       mm_log (tmp,ERROR);
  314.       strcpy ((*adr)->host,domainname);
  315.     }
  316.   }
  317.   return self;
  318. }
  319.  
  320.  
  321. // Find address book entry given nickname
  322.  
  323. - (int) find:(char *) t
  324. {
  325.   char key[TMPLEN],tmp[TMPLEN];
  326.   int i,m;
  327.                 // make sure there is something to search
  328.   if (t && strlen (t) && ucase (strcpy (key,t))) {
  329.                 // get size of browser
  330.     [browser getNumRows:&m numCols:&i];
  331.     while (m--)            // scan through browser
  332.       if (!strcmp (key,ucase    // have a match?
  333.            (strcpy (tmp,(char *) [[browser cellAt:m :0] nickName]))))
  334.     return m;        // yes, return the index
  335.    }
  336.   return -1;            // failed
  337. }
  338.  
  339.  
  340. // Address book has been updated
  341.  
  342. - update
  343. {
  344.   int i,m;
  345.   char tmp[TMPLEN];
  346.   id cell;
  347.   char *e;
  348.   NXStream *book = NXOpenMemory (NIL,0,NX_WRITEONLY);
  349.   if (!book) mm_log ("Can't open memory stream to save address book",ERROR);
  350.   else {            // get size of browser
  351.     [browser getNumRows:&m numCols:&i];
  352.     for (i = 0; i < m; i++) {    // for each entry
  353.                 // see if any extra stuff
  354.       e = (char *) [(cell = [browser cellAt:i :0]) extra];
  355.                 // dump the entry
  356.       NXPrintf (book,e ? "%s\t%s\t%s\t%s\n" : "%s\t%s\t%s\n",
  357.         [cell nickName],[cell fullName],[cell address],e);
  358.     }
  359.     NXFlush (book);        // spit the poop out
  360.                 // make address book file name
  361.     strcat (strcpy (tmp,(char *) NXHomeDirectory ()),bookfile);
  362.                 // write the file
  363.     if (NXSaveToFile (book,tmp)) mm_log ("Can't save address book",ERROR);
  364.                 // flush the stream
  365.     NXCloseMemory (book,NX_FREEBUFFER);
  366.   }
  367.                 // update the browser
  368.   [[browser sizeToCells] display];
  369.   [entry selectTextAt:0];    // select nickname
  370.   return self;
  371. }
  372.  
  373. @end
  374.