home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / x / volume19 / xmail / part02 < prev    next >
Encoding:
Text File  |  1993-04-27  |  57.4 KB  |  1,645 lines

  1. Newsgroups: comp.sources.x
  2. From: markham@cadence.com (Jeff Markham)
  3. Subject: v19i027:  xmail - X Window System interface to the mail program, Part02/10
  4. Message-ID: <1993Mar10.202514.10113@sparky.imd.sterling.com>
  5. X-Md4-Signature: 04471a1a7b019193563255af4c116e2b
  6. Date: Wed, 10 Mar 1993 20:25:14 GMT
  7. Approved: chris@sparky.imd.sterling.com
  8.  
  9. Submitted-by: markham@cadence.com (Jeff Markham)
  10. Posting-number: Volume 19, Issue 27
  11. Archive-name: xmail/part02
  12. Environment: X11
  13. Supersedes: xmail: Volume 15, Issue 18-26
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # Contents:  callbacks.c patchlevel.h
  20. # Wrapped by chris@sparky on Wed Mar 10 14:17:44 1993
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 2 (of 10)."'
  24. if test -f 'callbacks.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'callbacks.c'\"
  26. else
  27.   echo shar: Extracting \"'callbacks.c'\" \(54803 characters\)
  28.   sed "s/^X//" >'callbacks.c' <<'END_OF_FILE'
  29. X/*
  30. X * xmail - X window system interface to the mail program
  31. X *
  32. X * Copyright 1990,1991,1992 by National Semiconductor Corporation
  33. X *
  34. X * Permission to use, copy, modify, and distribute this software and its
  35. X * documentation for any purpose is hereby granted without fee, provided that
  36. X * the above copyright notice appear in all copies and that both that
  37. X * copyright notice and this permission notice appear in supporting
  38. X * documentation, and that the name of National Semiconductor Corporation not
  39. X * be used in advertising or publicity pertaining to distribution of the
  40. X * software without specific, written prior permission.
  41. X *
  42. X * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  43. X * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  44. X * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  45. X * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  46. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  47. X * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  48. X * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  49. X * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  50. X * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  51. X * PERFORMANCE OF THIS SOFTWARE.
  52. X *
  53. X * Author:  Michael C. Wagnitz - National Semiconductor Corporation
  54. X *
  55. X */
  56. X
  57. X
  58. X#include "global.h"
  59. X#include "MailwatchP.h"
  60. X#include "xmailregexp.h"
  61. X#include <sys/wait.h>
  62. X#include <sys/stat.h>
  63. X#include <sys/types.h>
  64. X#include <signal.h>
  65. X#include <errno.h>
  66. X#include <pwd.h>
  67. X
  68. X#ifdef vms
  69. Xextern int    noshare errno;
  70. Xextern int    noshare sys_nerr;
  71. Xextern char    noshare *sys_errlist[];
  72. X#else
  73. Xextern int    errno;
  74. Xextern int    sys_nerr;
  75. Xextern char    *sys_errlist[];
  76. X#endif
  77. X
  78. Xextern    char    otherBuf[BUFSIZ];
  79. X
  80. X#if ! defined(SIGCHLD) && defined(SIGCLD)
  81. X#define    SIGCHLD        SIGCLD
  82. X#endif
  83. X
  84. X/*
  85. X** @(#)Autograph() - Add user's Sign or sign autograph to outgoing mail
  86. X**                   Then make button insensitive, to prevent multiple calls.
  87. X**                   If requested autograph signature does not exist, tell user.
  88. X**             Because we can now be called by a translation table entry,
  89. X**             check to see if already insensitive before proceeding.
  90. X*/
  91. X/* ARGSUSED */
  92. XXtCallbackProc
  93. XAutograph(w, C, call_data)
  94. XWidget    w;
  95. Xcaddr_t    C;
  96. Xcaddr_t    call_data;        /* unused */
  97. X{
  98. X int        n;
  99. X String        cp, autograph;
  100. X char        tmp[BUFSIZ];
  101. X FILE        *fp;
  102. X struct stat    st_buf;
  103. X
  104. X
  105. X if (XtIsSensitive(w)) {     /* if okay to proceed... */
  106. X    (void) strcpy(tmp, "Sign");  /* Default action is to use Sign autograph */
  107. X    if (*C == 'a') tmp[0] = 's';
  108. X    autograph = GetMailEnv(tmp); /* First, see if an autograph entry exists */
  109. X
  110. X    if (! autograph) {
  111. X       /*
  112. X       ** If no Sign or sign, see if the user has created a .signature file
  113. X       */
  114. X       st_buf.st_size = 0;
  115. X       (void) sprintf(tmp, "%s/.Signature", HOME);
  116. X       if (*C == 'a')
  117. X          (void) sprintf(tmp, "%s/.signature", HOME);
  118. X       if (stat(tmp, &st_buf) != -1 &&
  119. X           st_buf.st_size < BUFSIZ &&
  120. X          (fp = fopen(tmp, "r")) != NULL) {
  121. X          autograph = (String) XtMalloc((unsigned) st_buf.st_size + 1);
  122. X          n = fread(autograph, sizeof(char), (int) st_buf.st_size, fp);
  123. X          autograph[n] = '\0';
  124. X          (void) fclose(fp);
  125. X         } else {
  126. X          (void) strcpy(tmp, "Cannot find a 'Sign'ature to append\n");
  127. X          if (*C == 'a') tmp[15] = 's';
  128. X          if (st_buf.st_size) {
  129. X             (void) sprintf(tmp,"Cannot append your .Signature (exceeds %d characters)\n",
  130. X                    BUFSIZ - 1);
  131. X             if (*C == 'a') tmp[20] = 's';
  132. X            }
  133. X          Bell(tmp);
  134. X          return;
  135. X         }
  136. X      } else {
  137. X       if (strlen(autograph) >= BUFSIZ) {
  138. X          (void) sprintf(tmp,"Cannot append your Signature (exceeds %d characters)\n",
  139. X                    BUFSIZ - 1);
  140. X          if (*C == 'a') tmp[19] = 's';
  141. X          Bell(tmp);
  142. X          XtFree((String) autograph);
  143. X          return;
  144. X         }
  145. X      }
  146. X
  147. X    XtSetSensitive(w, False);    /* Don't let us be pressed more than once */
  148. X    if (*C == 'A')        /* also make other sign button inoperative */
  149. X       XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), False);
  150. X    else            /* if this was a request for lowercase sign */
  151. X       XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), False);
  152. X
  153. X    for (cp = autograph, n = 0; n < BUFSIZ - 1 && *cp; cp++)
  154. X        if (*cp == '\\' && *(cp + 1) == 'n') {
  155. X           tmp[n++] = '\n';    /* Replace newline strings with a character */
  156. X           cp++;
  157. X          } else tmp[n++] = *cp;
  158. X
  159. X    if (tmp[n - 1] != '\n')    /* make sure msg ends with a newline */
  160. X       tmp[n++] = '\n';
  161. X    tmp[n] = '\0';
  162. X
  163. X    if ((fp = fopen(tmpName, "a")) != NULL) {
  164. X       if (*tmp != '-' || *(tmp + 1) != '-')    /* add a signature separator */
  165. X          (void) fwrite("-- \n", sizeof(char), 4, fp);
  166. X       (void) fwrite(tmp, sizeof(* tmp), strlen(tmp), fp);
  167. X       (void) fclose(fp);
  168. X      }
  169. X    XtFree((String) autograph);
  170. X   } /* end - if we were currently sensitive */
  171. X} /* Autograph */
  172. X
  173. X
  174. X/*
  175. X** @(#)endDelivery() - catch the signal when the delivery child finishes
  176. X*/
  177. Xint
  178. XendDelivery(signum)
  179. Xint    signum;
  180. X{
  181. X int    status;
  182. X
  183. X
  184. X if (signum == SIGCHLD &&
  185. X     mailpid != wait(&status))        /* in case mail child was what died */
  186. X (void) signal(SIGCHLD, SIG_DFL);    /* turn off the endDelivery hook */
  187. X
  188. X return 1;
  189. X} /* endDelivery */
  190. X
  191. X
  192. X/*
  193. X** @(#)DoCopy() - send a copy of the message to the indicated folder file
  194. X*/
  195. XDoCopy(file, to, subject, inreply, cc, bcc, outfolder, edits, add_face)
  196. Xchar    *file, *to, *subject, *inreply, *cc, *bcc;
  197. Xint    outfolder, edits, add_face;
  198. X{
  199. X int        len, n;
  200. X time_t        clock;
  201. X char        *m, tmp[BUFSIZ], From[BUFSIZ], Copy[BUFSIZ];
  202. X MailwatchWidget mb = (MailwatchWidget) XtNameToWidget(toplevel,"icon.mailbox");
  203. X FILE        *fp, *xf;
  204. X struct stat    st_buf;
  205. X
  206. X
  207. X if (file[0]) {
  208. X    st_buf.st_size = 0;            /* (in case msg file does not exist) */
  209. X    (void) stat(tmpName, &st_buf);
  210. X
  211. X    (void) time(&clock);
  212. X    (void) sprintf(From, "From %s %24.24s\n", mb->mailbox.username, (char *) ctime(&clock));
  213. X
  214. X    switch (file[0]) {
  215. X       case '|':            /* accomodate alias with Sun pipe cmd */
  216. X       (void) sprintf(Copy, "%s.pipe", tmpName);
  217. X                break;
  218. X       case '~':            /* file with a tilde expansion name */
  219. X          if (file[1] == '/')
  220. X             (void) sprintf(Copy, "%s%s", HOME, &file[1]);
  221. X          else {
  222. X             struct passwd *pw;
  223. X
  224. X             for (len = 0, n = 1; file[n] && file[n] != '/';)
  225. X                 tmp[len++] = file[n++];
  226. X             tmp[len] = '\0';
  227. X
  228. X             if (pw = getpwnam(tmp))
  229. X                (void) sprintf(Copy, "%s%s", pw->pw_dir, &file[n]);
  230. X             else (void) strcpy(Copy, file);
  231. X            }
  232. X                break;
  233. X       case '/':            /* file with an absolute path name */
  234. X                (void) strcpy(Copy, file);
  235. X                break;
  236. X       case '+':            /* file with a folder relative name */
  237. X                if (! foldir[0])
  238. X                   (void) strcpy(Copy, file);
  239. X                else
  240. X                   (void) sprintf(Copy, "%s%s", foldir, &file[1]);
  241. X                break;
  242. X
  243. X        default:
  244. X                if (file[0] == '.' && file[1] == '/')
  245. X                   (void) strcpy(Copy, file);
  246. X                else if (outfolder == 0 || ! foldir[0]) {
  247. X                   if (strchr(file, '/') == NULL)    /* no dir reference */
  248. X                      (void) strcpy(Copy, file);
  249. X                   else        /* assume file with dir is relative to home */
  250. X                      (void) sprintf(Copy, "%s/%s", HOME, file);
  251. X                  } else {    /* if outfolder (and folder name is included) */
  252. X                      (void) sprintf(Copy, "%s%s", foldir, file);
  253. X                  }
  254. X                break;
  255. X      }
  256. X
  257. X    if ((fp = fopen(Copy, "a")) == NULL) {
  258. X       /*
  259. X       ** Can't use the Bell routine internally, because we're a child.
  260. X       ** So, just pump the message to stderr and let user deal with it.
  261. X       */
  262. X       (void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
  263. X              (errno < sys_nerr)? sys_errlist[errno]:"Unknown error");
  264. X       (void) fprintf(stderr, tmp);
  265. X      } else {
  266. X                     (void) fprintf(fp, From);
  267. X       if (*to)      (void) fprintf(fp, "To: %s\n", to);
  268. X       if (*subject) (void) fprintf(fp, "Subject: %s\n", subject);
  269. X       if (*inreply) (void) fprintf(fp, "%s\n", inreply);
  270. X       /*
  271. X       ** Add support for custom header information as a resource
  272. X       ** and for editheaders mail option.  If editheaders, find
  273. X       ** custom header information in message text.
  274. X       */
  275. X       if (edits) {
  276. X          int    skip;
  277. X
  278. X
  279. X          if (st_buf.st_size) {
  280. X             xf = fopen(tmpName, "r");
  281. X             while (fgets(tmp, BUFSIZ, xf) != NULL) {
  282. X                if (tmp[0] == '\n') break;
  283. X                if (tmp[0] != ' ' && tmp[0] != '\t') skip = 0;
  284. X                if (strncmp(tmp,"To: ", 4) == 0) { skip = 1; continue; }
  285. X                if (strncmp(tmp,"Subject: ", 9) == 0) { skip = 1; continue; }
  286. X                if (strncmp(tmp,"In-Reply-To: ",13)==0) { skip = 1; continue; }
  287. X                if (strncmp(tmp,"Forwarding: ",12)==0) { skip = 1; continue; }
  288. X                if (strncmp(tmp,"Cc: ", 4) == 0) { skip = 1; continue; }
  289. X                if (strncmp(tmp,"Bcc: ", 5) == 0) { skip = 1; continue; }
  290. X                if (! skip) (void) fprintf(fp, "%s", tmp);
  291. X               }
  292. X             (void) fclose(xf);
  293. X            } else
  294. X             if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
  295. X               {
  296. X                if (m[0] == '"' || m[0] == "'"[0]) {
  297. X                   bcopy(m + 1, m, strlen(m) - 1);
  298. X                   while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
  299. X                         LASTCH(m) = '\0';
  300. X                  }
  301. X                if (LASTCH(m) != '\n')
  302. X                   (void) fprintf(fp, "%s\n", m);
  303. X                else
  304. X                   (void) fprintf(fp, "%s", m);
  305. X               }
  306. X         } else
  307. X       if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader")) {
  308. X           if (m[0] == '"' || m[0] == "'"[0]) {
  309. X              bcopy(m + 1, m, strlen(m) - 1);
  310. X              while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
  311. X                    LASTCH(m) = '\0';
  312. X             }
  313. X          if (LASTCH(m) != '\n')
  314. X                     (void) fprintf(fp, "%s\n", m);
  315. X          else
  316. X                     (void) fprintf(fp, "%s", m);
  317. X         }
  318. X       if (*cc)      (void) fprintf(fp, "Cc: %s\n", cc);
  319. X       if (*bcc)     (void) fprintf(fp, "Bcc: %s\n", bcc);
  320. X#ifdef X_FACE
  321. X       if (add_face) {
  322. X          (void) sprintf(tmp, "%s/.face", HOME);
  323. X          if (xf = fopen(tmp, "r")) {
  324. X             n = 1;
  325. X             while (fgets(tmp, BUFSIZ, xf) != NULL) {
  326. X                   if (n) {
  327. X                      n = 0;
  328. X                      if (strncmp(tmp, "X-Face:", 7) != 0)
  329. X                           (void) fprintf(fp, "X-Face:");
  330. X                     }
  331. X                   (void) fprintf(fp, "%s", tmp);
  332. X                  }
  333. X             (void) fclose(xf);
  334. X            }
  335. X         }
  336. X#endif /* X_FACE */
  337. X       (void) fprintf(fp, "\n");
  338. X       if (st_buf.st_size) {
  339. X          xf = fopen(tmpName, "r");
  340. X          while (fgets(tmp, BUFSIZ, xf) != NULL) {
  341. X                if (edits) {    /* if headers edited, drop them now */
  342. X                   if (tmp[0] == '\n') edits = 0;
  343. X                   continue;
  344. X                  }
  345. X                if (strncmp(tmp,"From ",5) == 0) (void)fprintf(fp,">");
  346. X                (void) fprintf(fp, "%s", tmp);
  347. X               }
  348. X          (void) fclose(xf);
  349. X          if (*tmp != '\n')
  350. X             (void) fprintf(fp, "\n");
  351. X         }
  352. X       (void) fclose(fp);
  353. X       if (file[0] == '|') {
  354. X          (void) sprintf(tmp, "/bin/cat %s %s", Copy, file);
  355. X          (void) system(tmp);
  356. X          (void) unlink(Copy);
  357. X         }
  358. X      } /* end - if we opened the target file successfully */
  359. X   } /* end - if passed file variable is not null */
  360. X} /* end - DoCopy */
  361. X
  362. X
  363. X/*
  364. X** @(#)Done() - Send composed message - if closure data says "Deliver"
  365. X*/
  366. X/* ARGSUSED */
  367. XXtCallbackProc
  368. XDone(w, closure, call_data)
  369. XWidget w;
  370. Xcaddr_t closure;
  371. Xcaddr_t call_data;
  372. X{
  373. X int        outfolder, n, len, edit_headers;
  374. X int        add_face = 1;        /* Are we using faces.sendmail script */
  375. X String        m, q, z, strchr();
  376. X char        record[BUFSIZ], Copy[BUFSIZ], tmp[BUFSIZ], addressees[BUFSIZ];
  377. X char        To[BUFSIZ], Subject[BUFSIZ], Cc[BUFSIZ], Bcc[BUFSIZ];
  378. X Widget        popup;
  379. X Arg        args[1];
  380. X FILE        *fp, *xf, *popen();
  381. X struct stat    st_buf;
  382. X struct passwd    *pw;
  383. X
  384. X
  385. X Bell(Default_Status_Info);
  386. X
  387. X popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
  388. X if (! popup) return;            /* SOMEthing would be VERY wrong here */
  389. X
  390. X XtPopdown(popup);            /* remove from view but don't destroy */
  391. X XWarpPointer(XtDisplay(toplevel), None,
  392. X              XtWindow(XtNameToWidget(toplevel, "topBox.textWindow.text")),
  393. X              0,0,0,0, XMail.helpX * 2, XMail.helpY);
  394. X
  395. X st_buf.st_size = 0;            /* (in case msg file does not exist) */
  396. X (void) stat(tmpName, &st_buf);
  397. X record[0] = Copy[0] = tmp[0] = addressees[0] = '\0';
  398. X To[0] = Subject[0] = Cc[0] = Bcc[0] = '\0';
  399. X
  400. X if (strcmp(closure, "Deliver") != 0) {
  401. X    /*
  402. X    ** Restore sensitivity of the Autograph, Send, and reply for next time
  403. X    */
  404. X    XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True);
  405. X    XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True);
  406. X    XtSetSensitive(XtParent(popup), True);
  407. X    XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), True);
  408. X    n = st_buf.st_size;        /* the number of bytes in the message text */
  409. X    if (n == 0 && *closure == 'c')
  410. X       Bell("No text to save in your dead letter file\n");
  411. X    else {
  412. X       if (n && (*closure == 'c' || ! Confirm("REALLY discard this text"))) {
  413. X          if (! (m = GetMailEnv("DEAD")))
  414. X             (void) sprintf(Copy, "%s/dead.letter", HOME);
  415. X          else {
  416. X             (void) strcpy(record, m);
  417. X             XtFree((String) m);
  418. X             if (record[0] != '~')
  419. X                (void) strcpy(Copy, record);    /* take whatever is given */
  420. X             else {
  421. X                if (record[1] == '/')
  422. X                   (void) sprintf(Copy, "%s%s", HOME, &record[1]);
  423. X                else {
  424. X                   for (len = 0, n = 1; record[n] && record[n] != '/';)
  425. X                       tmp[len++] = record[n++];
  426. X                   tmp[len] = '\0';
  427. X
  428. X                   if (pw = getpwnam(tmp))
  429. X                      (void) sprintf(Copy, "%s%s", pw->pw_dir, &record[n]);
  430. X                   else (void) strcpy(Copy, record);
  431. X                  }
  432. X               }
  433. X            }
  434. X          st_buf.st_size = -1;        /* see if our target exists */
  435. X          (void) stat(Copy, &st_buf);
  436. X          if (fp = fopen(Copy, "a")) {
  437. X             xf = fopen(tmpName, "r");
  438. X             while (fgets(tmp, BUFSIZ, xf) != NULL) {
  439. X                   if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
  440. X                   (void) fprintf(fp, "%s", tmp);
  441. X                  }
  442. X             (void) fclose(xf);
  443. X             if (*tmp != '\n')
  444. X                (void) fprintf(fp, "\n");
  445. X             (void) fclose(fp);
  446. X
  447. X             (void) sprintf(tmp, "\"%s\" [%s] (%d bytes)\n", Copy,
  448. X                 (st_buf.st_size >= 0) ? "Appended" : "New file", n);
  449. X             Bell(tmp);
  450. X            } else {
  451. X             (void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
  452. X                    (errno < sys_nerr)? sys_errlist[errno] : "Unknown error");
  453. X             Bell(tmp); 
  454. X            }
  455. X         }
  456. X      }                    /* end - if some message text exists */
  457. X    (void) unlink(tmpName);        /* remove the message text file */
  458. X   } else {                /* Deliver this message text */
  459. X    /*
  460. X    ** Call the alias() routine recursively, to de-alias the user's To:, Cc:,
  461. X    ** and Bcc: fields.
  462. X    */
  463. X    To[0] = Subject[0] = Cc[0] = Bcc[0] = otherBuf[0] = '\0';
  464. X    /*
  465. X    ** Retrieve current values from the header buffers
  466. X    */
  467. X    m = NULL;
  468. X    XtSetArg(args[0], XtNstring, &m);
  469. X    XtGetValues(XtNameToWidget(popup, "*SubjCc*To"), args, 1);
  470. X    if (m && *m) {
  471. X       (void) strncpy(addressees, m, BUFSIZ);
  472. X       (void) strncpy(To, m, BUFSIZ);    /* in case there's no user recipient */
  473. X       /*
  474. X       ** alias() adds filenames to a list and returns just user addresses
  475. X       ** (it also automatically wraps long header lines)
  476. X       */
  477. X       for (m = alias(addressees); strcmp(m, addressees); m = alias(addressees))
  478. X           (void) strncpy(addressees, m, BUFSIZ);
  479. X       if (addressees[0])        /* if some real users are named... */
  480. X          (void) strncpy(To, addressees, BUFSIZ);
  481. X      }
  482. X    
  483. X    m = NULL;
  484. X    XtSetArg(args[0], XtNstring, &m);
  485. X    XtGetValues(XtNameToWidget(popup, "*SubjCc*Subject"), args, 1);
  486. X
  487. X    if ((! addressees[0] && ! otherBuf[0]) || (! *m && st_buf.st_size == 0)) {
  488. X       if (! addressees[0])
  489. X          Bell("No recipient specified\n"); 
  490. X       else
  491. X          Bell("No subject and no message body\n"); 
  492. X       Waiting = TRUE;        /* so popup's EnterNotify won't overwrite msg */
  493. X       /*
  494. X       ** FORCE the user to either complete the message or abort delivery
  495. X       */
  496. X       XtPopup(popup, XtGrabNone);
  497. X
  498. X       XSync(XtDisplay(toplevel), False);
  499. X
  500. X       XtAddEventHandler(popup, StructureNotifyMask, False, warp_handler, NULL);
  501. X      } else {            /* if there is a message to be delivered... */
  502. X       /*
  503. X       ** Restore the sensitivity of the Autograph, Send, and reply buttons
  504. X       */
  505. X       XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True);
  506. X       XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True);
  507. X       XtSetSensitive(XtParent(popup), True);
  508. X       XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), True);
  509. X
  510. X       if (*m) {
  511. X          /*
  512. X          ** Format the subject line to wrap on ~70 characters.  In case the
  513. X          ** user didn't install the xmail default resources file, also look
  514. X          ** for imbedded newlines in the Subject text.
  515. X          */
  516. X          for (n = 0, len = 9; *m && n < BUFSIZ; n++, len++) {
  517. X              Subject[n] = *m++;
  518. X              if (Subject[n] == '\n') {
  519. X                 if (! *m) Subject[n] = '\0';
  520. X                 else if (len < 35) Subject[n] = ' ';
  521. X                      else { Subject[++n] = '\t'; len = 8; }
  522. X                } else if (len % 70 == 0)
  523. X                          if (Subject[n] == ' ') {
  524. X                             Subject[++n] = '\n';
  525. X                             Subject[++n] = '\t';
  526. X                             len = 8;
  527. X                            } else len--;    /* break at a word boundary */
  528. X             }
  529. X          Subject[n] = '\0';
  530. X         }
  531. X    
  532. X       m = NULL;
  533. X       XtSetArg(args[0], XtNstring, &m);
  534. X       XtGetValues(XtNameToWidget(popup, "*SubjCc*Cc"), args, 1);
  535. X       if (m && *m) {
  536. X          (void) strncpy(tmp, m, BUFSIZ);
  537. X          for (m = alias(tmp); strcmp(m, tmp); m = alias(tmp))
  538. X              (void) strncpy(tmp, m, BUFSIZ);
  539. X
  540. X          if (*m) {
  541. X             if (addressees[0]) (void) strcat(addressees, ", ");
  542. X             (void) strcat(addressees, m);
  543. X             (void) strncpy(Cc, m, BUFSIZ);
  544. X            }
  545. X         }
  546. X
  547. X       m = NULL;
  548. X       XtSetArg(args[0], XtNstring, &m);
  549. X       XtGetValues(XtNameToWidget(popup, "*SubjCc*Bcc"), args, 1);
  550. X       if (m && *m) {
  551. X          (void) strncpy(tmp, m, BUFSIZ);
  552. X          for (m = alias(tmp); strcmp(m, tmp); m = alias(tmp))
  553. X              (void) strncpy(tmp, m, BUFSIZ);
  554. X
  555. X          if (*m) {
  556. X             if (addressees[0]) (void) strcat(addressees, ", ");
  557. X             (void) strcat(addressees, m);
  558. X             (void) strncpy(Bcc, m, BUFSIZ);
  559. X            }
  560. X         }
  561. X       /*
  562. X       ** To avoid a bug in Sun's sendmail (for occasionally not being able to
  563. X       ** find the name of the real author of the message), strip commas from
  564. X       ** the address list and pass the recipient names to sendmail on the
  565. X       ** command line, ala Mail.  Also, strip all but the actual address from
  566. X       ** any compound addresses present in the list.
  567. X       */
  568. X       for (q = addressees; *q; q++) {
  569. X           if (*q == ',') {        /* remove any commas */
  570. X              if (q[1] == ' ') {    /* if comma is followed by a space */
  571. X                 for (m = q, z = q + 1; *z;) *m++ = *z++;
  572. X                 *m = '\0';        /* then shift string left by one */
  573. X                }
  574. X              else *q = ' ';        /* else substitute space for comma */
  575. X              q++;
  576. X             }
  577. X           if (*q == '\n' && *(q+1) == '\t') {    /* drop any newline tabs */
  578. X              for (m = q, z = q + 2; *z;) *m++ = *z++;
  579. X              *m = '\0';
  580. X             }
  581. X           if (z = strchr(q, ',')) {    /* find the end of next alias in list */
  582. X              n = (int) (z - q);
  583. X              for (m = tmp, z = q; *z && n--;) *m++ = *z++;
  584. X              *m = '\0';        /* shorten our search to just this */
  585. X              if ((m = strchr(tmp, '<')) || (m = strchr(tmp, '('))) {
  586. X                 if (*m == '<') {    /* if its a chevroned address type */
  587. X                    (void) sscanf(m, "<%[^>]>", Copy);
  588. X                    len = strlen(Copy);    /* save the address part of this only */
  589. X                    for (m = Copy; *m && len--;) *q++ = *m++;
  590. X                    for (m = q; *z;) *m++ = *z++;
  591. X                    *m = '\0';        /* shift rest of addressees left */
  592. X                    for (; *q && *q != ','; q++);
  593. X                    if (*q) q--;
  594. X                   } else {        /* must be a parenthetical style */
  595. X                    for (n = 0; tmp[n] && strchr(" \n\t", tmp[n]); n++);
  596. X                    if (1 == sscanf(&tmp[n], "%*[^)]) %s", Copy)) {
  597. X                       bcopy(Copy, q, strlen(Copy));
  598. X                       m = q + strlen(Copy);
  599. X                       bcopy(z, m, strlen(z) + 1);
  600. X                       if (q = strchr(q, ',')) q--;
  601. X                      } else {
  602. X                       (void) sscanf(&tmp[n], "%s", Copy);    /* address preceeds */
  603. X                       m = q + strlen(Copy);
  604. X                       bcopy(z, m, strlen(z) + 1);
  605. X                       if (q = strchr(q, ',')) q--;
  606. X                      }
  607. X                   }
  608. X                } else q = z - 1;    /* skip to alias end if not compound */
  609. X             } else {            /* last (or only) alias in the list */
  610. X              if ((m = strchr(q, '<')) || (m = strchr(q, '('))) {
  611. X                 if (*m == '<') {
  612. X                    if (! sscanf(q, "%*[^<]<%[^>]>", Copy))
  613. X                         (void) sscanf(q, "<%[^>]>", Copy);
  614. X                    bcopy(Copy, q, strlen(Copy) + 1);
  615. X                   } else {
  616. X                    for (z = q; strchr(" \n\t", *z); z++);
  617. X                    if (1 == sscanf(z, "%*[^)]) %s", Copy)) {
  618. X                       bcopy(Copy, q, strlen(Copy) + 1);
  619. X                      } else {
  620. X                       (void) sscanf(z, "%s", Copy);
  621. X                       z[strlen(Copy) + 1] = '\0';
  622. X                      }
  623. X                   }
  624. X                }
  625. X              break;            /* no more commas to be replaced */
  626. X             }
  627. X          }
  628. X
  629. X       if (! (m = GetMailEnv("sendmail")))
  630. X            m = XtNewString("/usr/lib/sendmail");
  631. X#ifdef X_FACE
  632. X       else {
  633. X          add_face = (strcmp(&m[strlen(m)-14], "faces.sendmail") != 0) ? 1 : 0;
  634. X         }
  635. X#endif /* X_FACE */
  636. X       /*
  637. X       ** The following arguments are passed to the sendmail command:
  638. X       **
  639. X       ** -oi    don't accept a dot on a line by itself as message termination
  640. X       **
  641. X       ** -om    send to "me" too, if I am a member of an alias expansion
  642. X       */
  643. X       (void) sprintf(tmp, "exec %s -oi -om %s\n", m, addressees);
  644. X       XtFree((String) m);
  645. X
  646. X       initfoldir();
  647. X
  648. X       if (m = GetMailEnv("outfolder")) {
  649. X          outfolder = 1;
  650. X          XtFree((String) m);
  651. X         } else outfolder = 0;
  652. X
  653. X       if (m = GetMailEnv("record")) {
  654. X          (void) strncpy(record, m, BUFSIZ);
  655. X          XtFree((String) m);
  656. X         } else record[0] = '\0';
  657. X
  658. X       if (m = GetMailEnv("editheaders")) {
  659. X          XtFree((String) m);
  660. X          edit_headers = 1;
  661. X         } else edit_headers = 0;
  662. X
  663. X       /*
  664. X       ** Fork a child process to effect the message delivery functions.
  665. X       */
  666. X       if ((n = fork()) != 0) {            /* if we are not the child */
  667. X          if (n == -1) {            /* delivery fork failed ... */
  668. X             if (errno == ENOMEM)
  669. X                Bell("Not enough core for message delivery child\n");
  670. X             else
  671. X                Bell("No more processes - no message delivery!?!\n");
  672. X            } else                /* parent sets delivery hook */
  673. X             (void) signal(SIGCHLD, endDelivery);
  674. X
  675. X          return;
  676. X         }
  677. X       /*
  678. X       ** Use this child process to effect our message delivery function.
  679. X       */
  680. X       (void) close(ConnectionNumber(XtDisplay(toplevel)));
  681. X
  682. X       if (addressees[0]) {        /* if there are primary addresses... */
  683. X          /*
  684. X          ** First, mail the header information and message text (in temporary
  685. X          ** file) using sendmail.  If we fail, we can't use the Bell routine
  686. X          ** because we are a child process, so write any complaints to stderr.
  687. X          */
  688. X          if (! (fp = popen(tmp, "w")))
  689. X             (void) fprintf(stderr, "xmail: Couldn't connect to sendmail.\n"); 
  690. X          else {
  691. X             if (To[0])      (void) fprintf(fp, "To: %s\n", To);
  692. X             if (Subject[0]) (void) fprintf(fp, "Subject: %s\n", Subject);
  693. X             if (InReply[0]) (void) fprintf(fp, "%s\n", InReply);
  694. X             /*
  695. X             ** Add support for custom header information as a resource
  696. X             ** and for editheaders mail option.  If editheaders, find
  697. X             ** custom header information in message text.
  698. X             */
  699. X             if (edit_headers) {
  700. X                int    skip;
  701. X
  702. X                if (st_buf.st_size) {
  703. X                   xf = fopen(tmpName, "r");
  704. X                   while (fgets(tmp, BUFSIZ, xf) != NULL) {
  705. X                      if (tmp[0] == '\n') break;
  706. X                      if (tmp[0] != ' ' && tmp[0] != '\t') skip = 0;
  707. X                      if (strncmp(tmp,"To: ", 4) == 0) {skip = 1; continue;}
  708. X                      if (strncmp(tmp,"Subject: ", 9) == 0) {skip=1;continue;}
  709. X                      if (strncmp(tmp,"In-Reply-To: ",13)==0) {skip=1;continue;}
  710. X                      if (strncmp(tmp,"Forwarding: ",12)==0) {skip=1;continue;}
  711. X                      if (strncmp(tmp,"Cc: ", 4) == 0) {skip = 1; continue;}
  712. X                      if (strncmp(tmp,"Bcc: ", 5) == 0) {skip = 1; continue;}
  713. X                      if (! skip) (void) fprintf(fp, "%s", tmp);
  714. X                     }
  715. X                   (void) fclose(xf);
  716. X                  } else
  717. X                   if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
  718. X                     {
  719. X                      if (m[0] == '"' || m[0] == "'"[0]) {
  720. X                         bcopy(m + 1, m, strlen(m) - 1);
  721. X                         while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
  722. X                               LASTCH(m) = '\0';
  723. X                        }
  724. X                      if (LASTCH(m) != '\n')
  725. X                         (void) fprintf(fp, "%s\n", m);
  726. X                      else
  727. X                         (void) fprintf(fp, "%s", m);
  728. X                     }
  729. X               } else
  730. X             if (m = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader"))
  731. X               {
  732. X                if (m[0] == '"' || m[0] == "'"[0]) {
  733. X                   bcopy(m + 1, m, strlen(m) - 1);
  734. X                   while (LASTCH(m) == '"' || LASTCH(m) == "'"[0])
  735. X                         LASTCH(m) = '\0';
  736. X                  }
  737. X                if (LASTCH(m) != '\n')
  738. X                   (void) fprintf(fp, "%s\n", m);
  739. X                else
  740. X                   (void) fprintf(fp, "%s", m);
  741. X               }
  742. X
  743. X             if (Cc[0])      (void) fprintf(fp, "Cc: %s\n", Cc);
  744. X             if (Bcc[0])     (void) fprintf(fp, "Bcc: %s\n", Bcc);
  745. X#ifdef X_FACE
  746. X             /*
  747. X             ** Look for, and add contents of, user's ~/.face file unless
  748. X             ** user is already invoking the faces.sendmail script, which
  749. X             ** does the job itself.  In that case, don't add info here.
  750. X             ** To accomodate both cases, look for and add header if none. 
  751. X             */
  752. X             if (add_face) {
  753. X                (void) sprintf(tmp, "%s/.face", HOME);
  754. X                if (xf = fopen(tmp, "r")) {
  755. X                   n = 1;
  756. X                   while (fgets(tmp, BUFSIZ, xf) != NULL) {
  757. X                         if (n) {
  758. X                            n = 0;
  759. X                            if (strncmp(tmp, "X-Face:", 7) != 0)
  760. X                                 (void) fprintf(fp, "X-Face:");
  761. X                           }
  762. X                         (void) fprintf(fp, "%s", tmp);
  763. X                        }
  764. X                   (void) fclose(xf);
  765. X                  }
  766. X               }
  767. X#endif /* X_FACE */
  768. X             (void) fprintf(fp, "\n");    /* separate the header from any text */
  769. X             /*
  770. X             ** Now write message text (if any) to the sendmail process.  ANY
  771. X             ** line which begins with the keyword ``From '' gets prepended
  772. X             ** with a greater than (>) symbol.
  773. X             */
  774. X             if (st_buf.st_size) {
  775. X                xf = fopen(tmpName, "r");
  776. X                len = edit_headers;
  777. X                while (fgets(tmp, BUFSIZ, xf) != NULL) {
  778. X                      if (len) {    /* if headers edited, drop them now */
  779. X                         if (tmp[0] == '\n') len = 0;
  780. X                         continue;
  781. X                        }
  782. X                      if (strncmp(tmp,"From ",5) == 0) (void) fprintf(fp, ">");
  783. X                      (void) fprintf(fp, "%s", tmp);
  784. X                     }
  785. X                (void) fclose(xf);
  786. X
  787. X                if (tmp[0] != '\n')
  788. X                   (void) fprintf(fp, "\n");    /* ensure a blank last line */
  789. X               }
  790. X             (void) pclose(fp);        /* this concludes sendmail delivery */
  791. X            }
  792. X          /*
  793. X          ** If user has set ``record'' in their .mailrc,
  794. X          ** add a message copy to that record file.
  795. X          */
  796. X          (void) DoCopy(record, To, Subject, InReply, Cc, Bcc,
  797. X                        outfolder, edit_headers, add_face);
  798. X
  799. X         }            /* end - if there are any primary addresses */
  800. X       /*
  801. X       ** If other addresses exist, send copies to those files or folders.
  802. X       */
  803. X       if (*otherBuf) {
  804. X          for (m = otherBuf; *m;) {
  805. X              for (q = m; *q && *q != ','; q++);
  806. X              if (*q == ',') {
  807. X                 *q = '\0';
  808. X                 n = 1;
  809. X                } else n = 0;
  810. X
  811. X              (void) DoCopy(m, To, Subject, InReply, Cc, Bcc,
  812. X                            outfolder, edit_headers, add_face);
  813. X
  814. X              q += n;
  815. X              m = q;
  816. X             }            /* end - for each record in otherBuf */
  817. X         }            /* end - if there were records in otherBuf */
  818. X       (void) unlink(tmpName);    /* remove any message text */
  819. X       exit(1);            /* the delivery child sub-process */
  820. X       /* NOTREACHED */
  821. X      }                /* end - if there was something to deliver */
  822. X   }                /* end - if we wanted to deliver a message */
  823. X} /* Done */
  824. X
  825. X
  826. X/*
  827. X** @(#)DoIt() - send command - passed via client_data argument - to mail
  828. X*/
  829. X/* ARGSUSED */
  830. XXtCallbackProc
  831. XDoIt(w, closure, call_data)
  832. XWidget        w;
  833. Xcaddr_t        closure;
  834. Xcaddr_t        call_data;
  835. X{
  836. X int        n;
  837. X Arg        args[1];
  838. X String        c, buf;
  839. X
  840. X
  841. X SetCursor(NORMAL);
  842. X (void) sprintf(Command, "%s\n", closure);
  843. X if (mailpid) {                /* If connections are okay,... */
  844. X    if ((n = match(command_pattern, Command)) != XM_C_FILE && n != XM_C_NEWMAIL) {
  845. X       SetCursor(WATCH);        /* will be reset by parser routine */
  846. X       writeMail(Command);
  847. X      } else {                /* check for commit of any changes */
  848. X       buf = NULL;
  849. X       XtSetArg(args[0], XtNlabel, &buf);
  850. X       XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
  851. X
  852. X       c = strrchr(buf, 'l');  if (c) c -= 2;
  853. X       if (! c || strncmp(c, "deleted", 7) != 0 ||
  854. X           strcmp(closure, "inc") == 0 ||
  855. X           Confirm("COMMIT all changes to this folder")) {
  856. X          writeMail(Command);
  857. X          SetCursor(WATCH);
  858. X          (void) strcpy(lastFolder, buf);    /* save for utimes update */
  859. X         }
  860. X      }
  861. X   } else if (XM_C_NEWMAIL != match(command_pattern, Command))
  862. X         Bell("No current mail connection\n");        /* if not 'Newmail' */
  863. X     else {
  864. X         SetCursor(WATCH);        /* will be reset by parser routine */
  865. X         if (mailargc > 2 && strcmp(mailargv[mailargc - 2], "-f") == 0) {
  866. X            mailargc -= 2;        /* throw away any folder argument */
  867. X            mailargv[mailargc] = NULL;    /* and NULL end of argument list */
  868. X           }
  869. X         callMail(mailargv);        /* restart the mail connections */
  870. X         (void) strcpy(Command, "Start"); /* Let em know we've re-started */
  871. X         UnsetNewmail(w, (caddr_t) NULL, (caddr_t) NULL);
  872. X         In_Bogus_Mail_File = False;    /* reset this so titleBar will chg */
  873. X        }
  874. X} /* DoIt */
  875. X
  876. X
  877. X/*
  878. X** @(#)DoPrint() - Call the PrintMsg action routine from a callback
  879. X*/
  880. X/* ARGSUSED */
  881. XXtCallbackProc
  882. XDoPrint(w, closure, call_data)
  883. XWidget    w;
  884. Xcaddr_t closure;
  885. Xcaddr_t    call_data;
  886. X{
  887. X PrintMsg(w, NULL, NULL, NULL);
  888. X} /* DoPrint */
  889. X
  890. X
  891. X/*
  892. X** @(#)DoQuit() - Terminate xmail after first closing mail connection
  893. X*/
  894. X/* ARGSUSED */
  895. XXtCallbackProc
  896. XDoQuit(w, closure, call_data)
  897. XWidget w;
  898. Xcaddr_t closure;
  899. Xcaddr_t call_data;
  900. X{
  901. X Arg        args[1];
  902. X String        c, buf;
  903. X
  904. X
  905. X if (mailpid) {                /* check for commit of any changes */
  906. X    buf = NULL;
  907. X    XtSetArg(args[0], XtNlabel, &buf);
  908. X    XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
  909. X
  910. X    c = strrchr(buf, 'l');  if (c) c -= 2;
  911. X    if (*closure != 'q' || ! c || strncmp(c, "deleted", 7) != 0 ||
  912. X        Confirm("Changes in folder.  REALLY quit")) {
  913. X       (void) sprintf(Command, "%s\n", closure);
  914. X       writeMail(Command);
  915. X      } else return;
  916. X   }
  917. X
  918. X XCloseDisplay(XtDisplay(toplevel));
  919. X
  920. X _exit(0);
  921. X} /* DoQuit */
  922. X
  923. X
  924. X/*
  925. X** @(#)DoSet() - send specified set request to mail and destroy current menu.
  926. X**         To accommodate those systems where mail cannot handle the
  927. X**         'set no' commands, convert 'set no's to unsets.
  928. X*/
  929. X/* ARGSUSED */
  930. XXtCallbackProc
  931. XDoSet(w, closure, call_data)
  932. XWidget    w;
  933. Xcaddr_t    closure;
  934. Xcaddr_t    call_data;
  935. X{
  936. X char    *c, buf[32];
  937. X
  938. X
  939. X if (! mailpid)
  940. X    Bell("No current mail connection\n");
  941. X else {
  942. X    SetCursor(WATCH);
  943. X    c = w->core.name;
  944. X    if (strlen(c) > 5 && strcmp(&c[strlen(c) - 6], "expert") == 0)
  945. X       if (*c == 'n')
  946. X            XMail.expert = (Boolean) 0;
  947. X       else XMail.expert = (Boolean) 1;
  948. X    else {
  949. X       if (*c == 'n')
  950. X          (void) sprintf(buf, "unset %s", &c[2]);
  951. X       else
  952. X          (void) sprintf(buf, "set %s", c);
  953. X
  954. X       c = QueryMail(buf);
  955. X      }
  956. X
  957. X    XtDestroyWidget(XtParent(XtParent(w)));
  958. X    SetCursor(NORMAL);
  959. X   }
  960. X} /* DoSet */
  961. X
  962. X
  963. X/* ARGSUSED */
  964. X/*
  965. X** @(#)DoWith() - send client_data command to mail with selected msg number
  966. X*/
  967. XXtCallbackProc
  968. XDoWith(w, client_data, call_data)
  969. XWidget    w;
  970. Xcaddr_t    client_data;
  971. Xcaddr_t    call_data;
  972. X{
  973. X int    num = 1;
  974. X
  975. X
  976. X Waiting = TRUE;        /* so popup's EnterNotify won't overwrite msg */
  977. X if (*client_data == 'n' || *client_data == '-')
  978. X    DoSelected(w, (XEvent *)NULL, &client_data, &num);
  979. X else if (! mailpid) Bell("No current mail connection\n");
  980. X else {
  981. X    SetCursor(WATCH);
  982. X    num = SelectionNumber(*client_data == 'u');
  983. X
  984. X    if (num) (void) sprintf(Command, "%s %d\n", client_data, num);
  985. X    else (void) sprintf(Command, "%s \n", client_data);
  986. X
  987. X    writeMail(Command);
  988. X   }
  989. X} /* DoWith */
  990. X
  991. X
  992. X/* ARGSUSED */
  993. X/*
  994. X** @(#)DropIt() - callback to destroy the current folder popup list(s)
  995. X*/
  996. XXtCallbackProc
  997. XDropIt(w, client_data, call_data)
  998. XWidget w;
  999. Xcaddr_t client_data;
  1000. Xcaddr_t call_data;
  1001. X{
  1002. X Widget    popup = XtNameToWidget(toplevel,"topBox.commandPanel.Folder.popupList");
  1003. X if (popup)
  1004. X    XtDestroyWidget(popup);
  1005. X SetCursor(NORMAL);
  1006. X} /* DropIt */
  1007. X
  1008. X
  1009. X/*
  1010. X** @(#)GetAliasName() - retrieve alias name from button label
  1011. X*/
  1012. X/* ARGSUSED */
  1013. XXtCallbackProc
  1014. XGetAliasName(w, shell, call_data)
  1015. XWidget        w;
  1016. XWidget        shell;
  1017. Xcaddr_t        call_data;        /* unused */
  1018. X{
  1019. X Arg        args[1];
  1020. X String        alias_name;
  1021. X
  1022. X
  1023. X XtSetArg(args[0], XtNlabel, &alias_name);
  1024. X XtGetValues(w, (ArgList) args, 1);    /* get this entry's label value */
  1025. X
  1026. X XtPopdown(XtParent(XtParent(w)));    /* aliasList<-table<-entry */
  1027. X
  1028. X if (TextGetLastPos(shell))        /* if some alias is already in there */
  1029. X    writeTo(shell, ", ", APPEND);    /* add comma separator between names */
  1030. X
  1031. X writeTo(shell, alias_name, APPEND);
  1032. X} /* GetAliasName */
  1033. X
  1034. X
  1035. X/*
  1036. X** @(#)GetFolderName() - retrieve full folder name from button labels
  1037. X*/
  1038. X/* ARGSUSED */
  1039. XXtCallbackProc
  1040. XGetFolderName(w, client_data, call_data)
  1041. XWidget    w;
  1042. Xcaddr_t    client_data, call_data;
  1043. X{
  1044. X Arg        args[1];
  1045. X int        k, n, x;
  1046. X String        folder_name;
  1047. X Widget        shell;
  1048. X char        tmp[BUFSIZ], buf[BUFSIZ];
  1049. X
  1050. X
  1051. X XtSetArg(args[0], XtNlabel, &folder_name);
  1052. X XtGetValues(w, (ArgList) args, 1);
  1053. X
  1054. X if (! call_data)                /* just a simple label name */
  1055. X    (void) sprintf(buf, "File: %s", folder_name);
  1056. X else {                        /* multiple stack of names */
  1057. X    tmp[0] = '\0';
  1058. X    shell = w;
  1059. X    (void) sscanf(call_data, "%d", &n);        /* using the nesting depth */
  1060. X
  1061. X    for (x = 1, k = (n * 2) + n - 1; k; k--) {
  1062. X        shell = shell->core.parent;        /* travel up the widget tree */
  1063. X        if (++x == 3) {                /* when we get to a label... */
  1064. X           x = 0;
  1065. X           (void) strcpy(buf, shell->core.name); /* stuff label name in */
  1066. X           (void) strcat(buf, tmp);        /* front of previous labels */
  1067. X           (void) strcpy(tmp, buf);        /* to build a complete path */
  1068. X          }
  1069. X       }
  1070. X    (void) sprintf(buf, "File: +%s%s", tmp, folder_name);
  1071. X   }
  1072. X writeTo(XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow"),
  1073. X         buf, REPLACE);
  1074. X} /* GetFolderName */
  1075. X
  1076. X
  1077. X/*
  1078. X** @(#)ReEdit() - Call the editMail routine to re-edit a message
  1079. X*/
  1080. X/* ARGSUSED */
  1081. XXtCallbackProc
  1082. XReEdit(w, closure, call_data)
  1083. XWidget    w;        /* unused */
  1084. Xcaddr_t closure;    /* unused */
  1085. Xcaddr_t    call_data;    /* unused */
  1086. X{
  1087. X Widget    Popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
  1088. X
  1089. X
  1090. X if (! Popup) {
  1091. X    XBell(XtDisplay(toplevel), 33);
  1092. X    return;                /* SOMEthing must be VERY wrong here */
  1093. X   }
  1094. X
  1095. X XtPopdown(Popup);            /* pop down the send popup */
  1096. X
  1097. X editMail();                /* re-edit the message file */
  1098. X} /* ReEdit */
  1099. X
  1100. X
  1101. X/*
  1102. X** @(#)Reply() - send a reply to the author of the selected message
  1103. X**               include its text and/or copy the other recipients, if asked.
  1104. X*/
  1105. X/* ARGSUSED */
  1106. XXtCallbackProc
  1107. XReply(w, client_data, call_data)
  1108. XWidget w;
  1109. Xcaddr_t client_data;
  1110. Xcaddr_t call_data;
  1111. X{
  1112. X int        n, fd, alwaysIgnore, edit_headers, erasable = 0;
  1113. X String        p, q, r, txt;
  1114. X char        *us, *getlogin();
  1115. X char        oldFrom[BUFSIZ], author[BUFSIZ], returnPath[BUFSIZ];
  1116. X char        toList[BUFSIZ], date[BUFSIZ], subject[BUFSIZ], ccList[BUFSIZ];
  1117. X char        Recipient[BUFSIZ];
  1118. X Widget        sb = XtNameToWidget(toplevel, "topBox.commandPanel.Send");
  1119. X#if defined(SIGACTION)
  1120. X struct sigaction *ovec; 
  1121. X (void) sigaction(SIGCHLD, NULL, &ovec);
  1122. X if (ovec.sa_handler != SIG_DFL)
  1123. X#else
  1124. X struct    sigvec    ovec;
  1125. X
  1126. X (void) sigvec(SIGCHLD, NULL, &ovec);
  1127. X if (ovec.sv_handler != SIG_DFL)
  1128. X#endif
  1129. X   {
  1130. X    Bell("Still delivering your previous message.  Please try again later.\n");
  1131. X    return;
  1132. X   }
  1133. X
  1134. X XtSetSensitive(sb, False);    /* Don't start more than one composition */
  1135. X XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), False);
  1136. X
  1137. X oldFrom[0] = author[0] = returnPath[0] = date[0] = subject[0] = '\0';
  1138. X ccList[0] = toList[0] = '\0';
  1139. X
  1140. X if (p = GetMailEnv("editheaders")) {
  1141. X    XtFree((String) p);
  1142. X    edit_headers = 1;
  1143. X   } else edit_headers = 0;
  1144. X
  1145. X if (*client_data != 's' || edit_headers) {
  1146. X    if ((fd = open(tmpName, O_WRONLY | O_CREAT, 0600)) == -1) {
  1147. X       Bell("xmail: Cannot open the temp file\n");
  1148. X       return;
  1149. X      }
  1150. X
  1151. X    if (p = GetMailEnv("alwaysignore")) {
  1152. X       XtFree((String) p);
  1153. X       alwaysIgnore = (strchr("SRA", *client_data)) ? 1 : 0;
  1154. X      } else alwaysIgnore = 0;
  1155. X
  1156. X    if (alwaysIgnore)        /* do we need to include a limited copy? */
  1157. X       (void) sprintf(Command, "p %d", SelectionNumber(False));
  1158. X    else
  1159. X       (void) sprintf(Command, "P %d", SelectionNumber(False));
  1160. X
  1161. X    if ((p = GetMailEnv("indentprefix")) != NULL)
  1162. X       erasable = 1;
  1163. X    else
  1164. X       p = "\t";
  1165. X
  1166. X    txt = QueryMail(Command);
  1167. X
  1168. X    switch (*client_data) {
  1169. X       case 'S':
  1170. X            (void) write(fd, "---------- Begin Forwarded Message ----------\n", 46);
  1171. X            /*
  1172. X            ** Any lines that begin with keyword 'From ' get a leading symbol
  1173. X            */
  1174. X            for (q = r = txt; *r;) {
  1175. X                for (; *r && *r != '\n'; r++);
  1176. X                    if (*r == '\n') {        /* For each line of text */
  1177. X                       if (strncmp(q, "From ", 5) == 0)
  1178. X                          (void) write(fd, ">", 1);
  1179. X                       (void) write(fd, q, r - q + 1);
  1180. X                       q = ++r;
  1181. X                      }
  1182. X               }
  1183. X            if (*q) {                /* should never happen, but. */
  1184. X               if (strncmp(q, "From ", 5) == 0)
  1185. X                  (void) write(fd, ">", 1);
  1186. X               (void) write(fd, q, strlen(q));    /* write last line of text */
  1187. X               if (LASTCH(q) != '\n')
  1188. X                  (void) write(fd, "\n", 1);
  1189. X              }
  1190. X            (void) write(fd, "----------- End Forwarded Message -----------\n", 46);
  1191. X            break;
  1192. X       case 'R':
  1193. X       case 'A':
  1194. X            n = strlen(p);
  1195. X            for (q = r = txt; *r;) {
  1196. X                for (; *r && *r != '\n'; r++);
  1197. X                    if (*r == '\n') {        /* For each line of insert */
  1198. X                       (void) write(fd, p, n);    /* write indent prefix, */
  1199. X                       (void) write(fd, q, r - q + 1);    /* followed by text */
  1200. X                       q = ++r;
  1201. X                      }
  1202. X               }
  1203. X            if (*q) {                /* should never happen, but. */
  1204. X               (void) write(fd, p, n);        /* write the indent prefix, */
  1205. X               (void) write(fd, q, strlen(q));    /* this last line of text, */
  1206. X               if (LASTCH(q) != '\n')
  1207. X                  (void) write(fd, "\n", 1);    /* and an ending newline. */
  1208. X              }
  1209. X            if (erasable)
  1210. X               XtFree((String) p);
  1211. X            break;
  1212. X      } /* end - switch on client_data */
  1213. X
  1214. X    (void) close(fd);
  1215. X
  1216. X    if (alwaysIgnore) {        /* get full headers for data (top 100 lines) */
  1217. X       txt = QueryMail("unset alwaysignore");
  1218. X       (void) sprintf(Command, "top %d", SelectionNumber(False));
  1219. X       txt = QueryMail(Command);
  1220. X      }
  1221. X    /*
  1222. X    ** strip header information from the original message
  1223. X    */
  1224. X    for (p = txt; *p; p++) {
  1225. X        if (*p == '\n' || strncmp(p, "Status:", 7) == 0) break;
  1226. X
  1227. X        if (strncmp(p, "From ", 5) == 0 ) {
  1228. X           bzero(oldFrom, BUFSIZ);
  1229. X           p += 5;
  1230. X           for (q = p; *q && *q != ' ' && *q != '\n'; q++);
  1231. X           (void) strncpy(oldFrom, p, q - p);    /* drop the date portion now */
  1232. X           for (; *q && *q != '\n'; q++);    /* skip to end of this line */
  1233. X           p = q;
  1234. X          }
  1235. X
  1236. X        else if (strncmp(p, "Return-Path:", 12) == 0) {
  1237. X           bzero(returnPath, BUFSIZ);
  1238. X           p += 13;
  1239. X           for (q = p; *q && *q != '\n'; q++);
  1240. X           (void) strncpy(returnPath, p, q - p); /* drop trailing newline */    
  1241. X           p = q;
  1242. X          }
  1243. X
  1244. X        else if (strncmp(p, "Date:", 5) == 0) {
  1245. X           bzero(date, BUFSIZ);
  1246. X           p += 6;
  1247. X           for (q = p; *q && *q != '\n'; q++);
  1248. X           (void) strncpy(date, p, q - p);
  1249. X           p = q;
  1250. X          }
  1251. X
  1252. X        else if (strncmp(p, "From:", 5) == 0) {
  1253. X           bzero(author, BUFSIZ);
  1254. X           p += 6;
  1255. X           for (q = p; *q && *q != '\n'; q++);
  1256. X           while (*(q+1) && strchr(" \t", *(q+1))) {
  1257. X                 *q = ' ';        /* change this newline to a space */
  1258. X                 *(q+1) = ' ';        /* change possible tab to a space */
  1259. X                 for (q++; *q && *q != '\n'; q++);
  1260. X                }
  1261. X           (void) strncpy(author, p, q - p);
  1262. X           p = q;
  1263. X          }
  1264. X
  1265. X        else if (strncmp(p, "To:", 3) == 0) {
  1266. X           bzero(toList, BUFSIZ);
  1267. X           p += 4;
  1268. X           for (q = p; *q && *q != '\n'; q++);
  1269. X           while (*(q+1) && strchr(" \t", *(q+1))) {
  1270. X                 *q = ' ';        /* change this newline to a space */
  1271. X                 *(q+1) = ' ';        /* change possible tab to a space */
  1272. X                 for (q++; *q && *q != '\n'; q++);
  1273. X                }
  1274. X           if (*client_data == 'a' || *client_data == 'A')
  1275. X              (void) strncpy(toList, p, q - p);
  1276. X           p = q;
  1277. X          }
  1278. X
  1279. X        else if (strncmp(p, "Subject:", 8) == 0) {
  1280. X           bzero(subject, BUFSIZ);
  1281. X           p += 9;
  1282. X           for (q = p; *q && *q != '\n'; q++);
  1283. X           while (*(q+1) && strchr(" \t", *(q+1))) {
  1284. X                 *q = ' ';        /* change this newline to a space */
  1285. X                 *(q+1) = ' ';        /* change possible tab to a space */
  1286. X                 for (q++; *q && *q != '\n'; q++);
  1287. X                }
  1288. X           (void) strncpy(subject, p, q - p);
  1289. X           p = q;
  1290. X          }
  1291. X
  1292. X        else if (strncmp(p, "Cc:", 3) == 0) {
  1293. X           bzero(ccList, BUFSIZ);
  1294. X           p += 4;
  1295. X           for (q = p; *q && *q != '\n'; q++);
  1296. X           while (*(q+1) && strchr(" \t", *(q+1))) {
  1297. X                 *q = ' ';        /* change this newline to a space */
  1298. X                 *(q+1) = ' ';        /* change possible tab to a space */
  1299. X                 for (q++; *q && *q != '\n'; q++);
  1300. X                }
  1301. X           if (*client_data == 'a' || *client_data == 'A')
  1302. X              (void) strncpy(ccList, p, q - p);
  1303. X           p = q;
  1304. X          }
  1305. X        else for (; *p && *p != '\n'; p++);
  1306. X       } /* end - for all of message body */
  1307. X
  1308. X    if (alwaysIgnore)            /* restore this if originally set */
  1309. X       p = QueryMail("set alwaysignore");
  1310. X
  1311. X    if (toList[0] != '\0') {        /* remove ourself from the list */
  1312. X       if (! (us = getlogin())) {
  1313. X          struct passwd *pw = getpwuid((uid_t) getuid());
  1314. X
  1315. X          if (pw)
  1316. X             us = pw->pw_name;
  1317. X          else
  1318. X             us = "no_name";
  1319. X         }
  1320. X       for (p = toList; *us && *p; p++) {
  1321. X           if (strncmp(p, us, strlen(us)) == 0) {
  1322. X              for (q = p + strlen(us); *q && *q != ',' && *q != ' '; q++);
  1323. X              for (; *q && (*q == ',' || *q == ' '); q++);
  1324. X              bcopy(q, p, strlen(q) + 1);
  1325. X              continue;
  1326. X             }
  1327. X           while (*p && *p != ',' && *p != ' ') p++;
  1328. X           while (*p && (*p == ',' || *p == ' ')) p++;
  1329. X           p--;
  1330. X          }
  1331. X      }
  1332. X   } /* end - if client_data does not equal 's' */
  1333. X
  1334. X InReply[0] = Recipient[0] = '\0';
  1335. X/*
  1336. X** If message did not have a 'From:', use 'Return-Path:' for reply recipient.
  1337. X** If message also did not have a 'Return-Path', use the older style 'From '.
  1338. X*/
  1339. X if (*client_data != 'S' && *client_data != 's') {
  1340. X    p = author;
  1341. X    if (! *p && returnPath[0]) 
  1342. X       p = returnPath;
  1343. X    if (! *p && oldFrom[0])
  1344. X       p = oldFrom;
  1345. X
  1346. X    (void) strcpy(Recipient, p);
  1347. X/*
  1348. X** If author's name consists of a compound address (i.e. name <address>,
  1349. X** (Name) address, or equivalents...) strip off the real address portion
  1350. X** (i.e. that portion not in parens, but possibly between chevrons).
  1351. X*/
  1352. X    if ((p = strchr(Recipient, '<')) || (p = strchr(Recipient, '(')))
  1353. X       switch (*p) {
  1354. X          case '<': q = strchr(p++, '>');
  1355. X                    *q = '\0';    /* '<address> Name' or 'Name <address>' */
  1356. X                    bcopy(p, Recipient, strlen(p) + 1);
  1357. X                    break;
  1358. X
  1359. X          case '(': q = strchr(p, ')');        /* skipping past the parens */
  1360. X                    if (p == Recipient) {    /* '(Name) address' format */
  1361. X                       for (q++; *q && (*q == ' ' || *q == '\t'); q++);
  1362. X                       bcopy(p, Recipient, strlen(p) + 1);
  1363. X                      } else {            /* 'address (Name)' format */
  1364. X                       for (; (p-1) > Recipient &&
  1365. X                              (*(p-1) == ' ' || *(p-1) == '\t'); p--);
  1366. X                       *p = '\0';
  1367. X                      }
  1368. X                    break;
  1369. X         }
  1370. X/*
  1371. X** If this sender wishes to include all recipients of the original message in
  1372. X** this response, include all others except this sender in that address list.
  1373. X*/
  1374. X    if (toList[0] && (*client_data == 'a' || *client_data == 'A')) {
  1375. X       if (LASTCH(Recipient) && LASTCH(Recipient) != ',' &&
  1376. X           strlen(Recipient) + 2 < BUFSIZ)
  1377. X          (void) strcat(Recipient, ", ");
  1378. X       if (strlen(Recipient) + strlen(toList) < BUFSIZ)
  1379. X          (void) strcat(Recipient, toList);
  1380. X       for (p = Recipient + strlen(Recipient) - 1; *p == ' ' || *p == ','; p--);
  1381. X       *++p = '\0';            /* drop any trailing ", " garbage */
  1382. X      }
  1383. X   }
  1384. X
  1385. X if (*client_data != 's' && author[0] && date[0]) {
  1386. X    r = (*client_data == 'S') ? "Forwarding" : "In-Reply-To";
  1387. X    (void) sprintf(InReply, "%s: Mail from '%s'\n%*sdated: %s", r, author,
  1388. X                   strlen(r) - 5, " ", date);
  1389. X   }
  1390. X
  1391. X sendMail(sb);
  1392. X
  1393. X fd = -1;
  1394. X if (edit_headers) {
  1395. X    (void) sprintf(Command, "%s_", tmpName);
  1396. X    if (rename(tmpName, Command))
  1397. X       Bell("xmail: Cannot rename edit file for editheaders\n");
  1398. X    else if ((fd = open(tmpName, O_WRONLY | O_CREAT, 0600)) < 0) {
  1399. X       Bell("xmail: Cannot reopen the edit file for editheaders\n");
  1400. X       return;
  1401. X      }
  1402. X   }
  1403. X
  1404. X if (! Recipient[0]) {
  1405. X    writeTo(XtNameToWidget(sb, "*To"), "", REPLACE);
  1406. X    if (fd >= 0) (void) write(fd, "To: \n", 5);
  1407. X   } else {
  1408. X    writeTo(XtNameToWidget(sb, "*To"), Recipient, REPLACE);
  1409. X    if (fd >= 0) {
  1410. X       if (*client_data == 's' && edit_headers)
  1411. X          (void) write(fd, "To: \n", 5);
  1412. X       else {
  1413. X          (void) write(fd, "To: ", 4);
  1414. X          (void) write(fd, Recipient, strlen(Recipient));
  1415. X          (void) write(fd, "\n", 1);
  1416. X         }
  1417. X      }
  1418. X   }
  1419. X
  1420. X if (! subject[0]) {
  1421. X    writeTo(XtNameToWidget(sb, "*Subject"), "", REPLACE);
  1422. X    if (fd >= 0) (void) write(fd, "Subject: \n", 10);
  1423. X   } else {
  1424. X    n = ((strchr("Rr", subject[0]) != NULL) &&
  1425. X         (strchr("Ee", subject[1]) != NULL) &&
  1426. X         (strchr(":;", subject[2]) != NULL));
  1427. X
  1428. X    if (n)
  1429. X       writeTo(XtNameToWidget(sb, "*Subject"), subject, REPLACE);
  1430. X    else {
  1431. X       writeTo(XtNameToWidget(sb, "*Subject"), "Re: ", REPLACE);
  1432. X       writeTo(XtNameToWidget(sb, "*Subject"), subject, APPEND);
  1433. X      }
  1434. X    if (fd >= 0) {
  1435. X       if (*client_data == 's' && edit_headers)
  1436. X          (void) write(fd, "Subject: \n", 10);
  1437. X       else {
  1438. X          (void) write(fd, "Subject: ", 9);
  1439. X          if (! n) (void) write(fd, "Re: ", 4);
  1440. X          (void) write(fd, subject, strlen(subject));
  1441. X          (void) write(fd, "\n", 1);
  1442. X
  1443. X          if (InReply[0]) {
  1444. X             (void) write(fd, InReply, strlen(InReply));
  1445. X             (void) write(fd, "\n", 1);
  1446. X            }
  1447. X         }
  1448. X
  1449. X       if (p = XGetDefault(XtDisplay(toplevel), "XMail", "customHeader")) {
  1450. X          if (p[0] == '"' || p[0] == "'"[0]) {
  1451. X             bcopy(p + 1, p, strlen(p) - 1);
  1452. X             while (LASTCH(p) == '"' || LASTCH(p) == "'"[0])
  1453. X                   LASTCH(p) = '\0';
  1454. X            }
  1455. X          (void) write(fd, p, strlen(p));
  1456. X          if (LASTCH(p) != '\n')
  1457. X             (void) write(fd, "\n", 1);
  1458. X         }
  1459. X      }
  1460. X   }
  1461. X
  1462. X if (! ccList[0]) {
  1463. X    writeTo(XtNameToWidget(sb, "*Cc"), "", REPLACE);
  1464. X    if (fd >= 0 && edit_headers)
  1465. X       (void) write(fd, "Cc: \n", 5);
  1466. X   } else {
  1467. X    writeTo(XtNameToWidget(sb, "*Cc"), ccList, REPLACE);
  1468. X    if (fd >= 0) {
  1469. X       (void) write(fd, "Cc: ", 4);
  1470. X       (void) write(fd, ccList, strlen(ccList));
  1471. X       (void) write(fd, "\n", 1);
  1472. X      }
  1473. X   }
  1474. X
  1475. X    writeTo(XtNameToWidget(sb, "*Bcc"), "", REPLACE);
  1476. X if (fd >= 0 && edit_headers)
  1477. X    (void) write(fd, "Bcc: \n", 6);
  1478. X
  1479. X if (fd >= 0) {
  1480. X    (void) write(fd, "\n", 1);
  1481. X    if ((erasable = open(Command, O_RDONLY)) < 0) {
  1482. X       Bell("xmail: Cannot reread the edit file for editheaders\n");
  1483. X       return;
  1484. X      }
  1485. X    (void) unlink(Command);
  1486. X    while (n = read(erasable, Command, BUFSIZ))
  1487. X          (void) write(fd, Command, n);
  1488. X    (void) close(erasable);
  1489. X    (void) close(fd);
  1490. X   }
  1491. X
  1492. X editMail();
  1493. X} /* Reply */
  1494. X
  1495. X
  1496. X/*
  1497. X** @(#)Save() - (or copy) a message to specified folder or mbox
  1498. X*/
  1499. X/* ARGSUSED */
  1500. XXtCallbackProc
  1501. XSave(w, cmd, call_data)
  1502. XWidget w;
  1503. Xcaddr_t cmd;
  1504. Xcaddr_t call_data;
  1505. X{
  1506. X int            num;
  1507. X String            p, r, FBuf;
  1508. X XawTextPosition    pos;
  1509. X Arg            args[1];
  1510. X Widget            fileWindow;
  1511. X
  1512. X
  1513. X if (! mailpid) Bell("No current mail connection\n");
  1514. X else {
  1515. X    SetCursor(WATCH);            /* reset by parser routines */
  1516. X    num = SelectionNumber(False);    /* no current message returns zero */
  1517. X    if (*cmd == 'C' || *cmd == 'S' || num == 0) {
  1518. X       if (num) {
  1519. X          (void) sprintf(Command, "%s %d\n", cmd, num);
  1520. X          Bell("");            /* Reset bell worthyness flag */
  1521. X         } else {
  1522. X          (void) sprintf(Command, "%s \n", cmd);
  1523. X         }
  1524. X      } else {
  1525. X       fileWindow = XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow");
  1526. X       pos = TextGetLastPos(fileWindow);
  1527. X       if (pos - StartPos > 0) {
  1528. X          XtSetArg(args[0], XtNstring, &FBuf);
  1529. X          XtGetValues(fileWindow, args, 1);
  1530. X
  1531. X          if (FBuf[pos] != '\0') FBuf[pos] = '\0';
  1532. X          p = XtNewString(&FBuf[StartPos]);
  1533. X          (void) sprintf(Command, "%s %d %s\n", cmd, num, p);
  1534. X          XtFree((String) p);
  1535. X         } else {
  1536. X          /*
  1537. X          ** If no specified filename, use the mbox pointer.  We MUST include
  1538. X          ** it here, because specifying the message number for the action
  1539. X          ** would be interpreted as a filename, if we didn't append one.
  1540. X          */
  1541. X          if (! (p = GetMailEnv("MBOX")))
  1542. X             (void) sprintf(Command, "%s %d %s/mbox\n", cmd, num, HOME);
  1543. X          else {
  1544. X             initfoldir();
  1545. X             if (*p != '+' && (*p == '/' || (*p == '.' && *(p+1) == '/') ||
  1546. X                  foldir[0] == NULL)) {
  1547. X                (void) sprintf(Command, "%s %d %s\n", cmd, num, p);
  1548. X               } else {
  1549. X                (void) sprintf(Command, "%s %d %s%s\n", cmd, num, foldir, (*p == '+') ? &p[1] : p);
  1550. X               }
  1551. X             XtFree((String) p);
  1552. X            }
  1553. X         }
  1554. X      }
  1555. X    writeMail(Command);
  1556. X   }
  1557. X} /* Save */
  1558. X
  1559. X
  1560. X/*
  1561. X** @(#)SetNewmail - Highlight Newmail button to attract user attention
  1562. X*/
  1563. X/* ARGSUSED */
  1564. XXtCallbackProc
  1565. XSetNewmail(w, client_data, call_data)
  1566. XWidget    w;            /* unused */
  1567. Xcaddr_t    client_data;        /* unused */
  1568. Xcaddr_t    call_data;        /* unused */
  1569. X{
  1570. X Widget    cw;
  1571. X
  1572. X if (! Highlighted) {
  1573. X    cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
  1574. X    XSetWindowBackgroundPixmap(XtDisplay(toplevel), XtWindow(cw), hatch);
  1575. X    XtUnmapWidget(cw);
  1576. X    XtMapWidget(cw);
  1577. X    Highlighted = 1;
  1578. X    reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 0);
  1579. X   }
  1580. X} /* SetNewmail */
  1581. X
  1582. X
  1583. X/*
  1584. X** @(#)UnsetNewmail - Remove Newmail button highlighting
  1585. X*/
  1586. X/* ARGSUSED */
  1587. XXtCallbackProc
  1588. XUnsetNewmail(w, client_data, call_data)
  1589. XWidget    w;            /* unused */
  1590. Xcaddr_t    client_data;        /* unused */
  1591. Xcaddr_t    call_data;        /* unused */
  1592. X{
  1593. X Widget    cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
  1594. X
  1595. X if (Highlighted) {
  1596. X    XSetWindowBackground(XtDisplay(toplevel), XtWindow(cw), cw->core.background_pixel);
  1597. X    XtUnmapWidget(cw);
  1598. X    XtMapWidget(cw);
  1599. X    Highlighted = 0;
  1600. X    reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 1);
  1601. X   }
  1602. X} /* UnsetNewmail */
  1603. END_OF_FILE
  1604.   if test 54803 -ne `wc -c <'callbacks.c'`; then
  1605.     echo shar: \"'callbacks.c'\" unpacked with wrong size!
  1606.   fi
  1607.   # end of 'callbacks.c'
  1608. fi
  1609. if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  1610.   echo shar: Will not clobber existing file \"'patchlevel.h'\"
  1611. else
  1612.   echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
  1613.   sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
  1614. X#define PATCHLEVEL 5
  1615. END_OF_FILE
  1616.   if test 21 -ne `wc -c <'patchlevel.h'`; then
  1617.     echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  1618.   fi
  1619.   # end of 'patchlevel.h'
  1620. fi
  1621. echo shar: End of archive 2 \(of 10\).
  1622. cp /dev/null ark2isdone
  1623. MISSING=""
  1624. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1625.     if test ! -f ark${I}isdone ; then
  1626.     MISSING="${MISSING} ${I}"
  1627.     fi
  1628. done
  1629. if test "${MISSING}" = "" ; then
  1630.     echo You have unpacked all 10 archives.
  1631.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1632. else
  1633.     echo You still must unpack the following archives:
  1634.     echo "        " ${MISSING}
  1635. fi
  1636. exit 0
  1637. exit 0 # Just in case...
  1638. -- 
  1639.   // chris@IMD.Sterling.COM            | Send comp.sources.x submissions to:
  1640. \X/  Amiga - The only way to fly!      |
  1641.  "It's intuitively obvious to the most |    sources-x@imd.sterling.com
  1642.   casual observer..."                  |
  1643.