home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume12 / mush / part11 < prev    next >
Text File  |  1990-05-05  |  56KB  |  1,889 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i039: Mail User's Shell, Part11/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 39
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part11
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 11 (of 19)."
  18. # Contents:  mush/makefile.bsd mush/misc.c mush/msgs.c
  19. # Wrapped by argv@turnpike on Wed May  2 13:59:35 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'mush/makefile.bsd' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'mush/makefile.bsd'\"
  23. else
  24. echo shar: Extracting \"'mush/makefile.bsd'\" \(2051 characters\)
  25. sed "s/^X//" >'mush/makefile.bsd' <<'END_OF_FILE'
  26. X# makefile.bsd    (c) copyright 1986    (Dan Heller)
  27. X# SunOS users should add -DSUN_3_5 or -DSUN_4_0 to the CFLAGS line below.
  28. X#
  29. XHDRS= mush.h config.h-dist strings.h bindings.h options.h version.h glob.h
  30. X
  31. XSRCS= main.c init.c misc.c mail.c hdrs.c execute.c commands.c print.c dates.c \
  32. X      signals.c setopts.c msgs.c pick.c sort.c expr.c folders.c \
  33. X      loop.c viewopts.c curses.c curs_io.c bind.c file.c strings.c \
  34. X      lock.c macros.c options.c addrs.c malloc.c glob.c
  35. XOBJS= main.o init.o misc.o mail.o hdrs.o execute.o commands.o print.o file.o \
  36. X      signals.o setopts.o msgs.o pick.o sort.o expr.o strings.o \
  37. X      folders.o dates.o loop.o viewopts.o curses.o curs_io.o bind.o \
  38. X      lock.o macros.o options.o addrs.o malloc.o glob.o
  39. X
  40. XHELP_FILES= README README-7.0 README-7.1 mush.1 cmd_help \
  41. X    Mushrc Mailrc Gnurc sample.mushrc advanced.mushrc digestify
  42. X
  43. XMAKES= makefile.bsd makefile.xenix makefile.sys.v makefile.hpux makefile.sun
  44. X
  45. X# See the README for changes needed to compile under Ultrix.
  46. X# In particular, you may need -DSIGRET=void and/or -ltermcap.
  47. XCFLAGS= -O -DCURSES -DBSD
  48. XLDFLAGS=
  49. XLINTFLAGS= -bxah -Dlint -DCURSES -DBSD
  50. XLIBES= -lcurses -ltermlib
  51. XOTHERLIBS=
  52. X# Use some variant of this one if you #define MMDF in config.h
  53. X#OTHERLIBS=/usr/src/mmdf/lib/libmmdf.a
  54. X
  55. Xmush: $(OBJS)
  56. X    @echo loading...
  57. X    @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush
  58. X
  59. X$(OBJS): config.h mush.h
  60. Xloop.o: version.h
  61. X
  62. Xtape:
  63. X    @tar cv $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES)
  64. X
  65. Xtar:
  66. X    @tar fcv MUSH $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES)
  67. X
  68. Xtarmail:
  69. X    tar fcv - $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES) | \
  70. X    compress | btoa > mush.tarmail
  71. X
  72. Xlint:
  73. X    lint $(LINTFLAGS) $(SRCS)
  74. X
  75. Xclean:
  76. X    rm -f *.o core mush
  77. X
  78. XBINDIR= /usr/local/bin
  79. XLIBDIR= /usr/local/lib
  80. XMRCDIR= /usr/lib
  81. XMANDIR= /usr/local/man/man1
  82. XMANEXT= 1
  83. X
  84. Xinstall: mush
  85. X    mv mush $(BINDIR)
  86. X    strip $(BINDIR)/mush
  87. X    chmod 0755 $(BINDIR)/mush
  88. X    cp mush.1 $(MANDIR)/mush.$(MANEXT)
  89. X    chmod 0644 $(MANDIR)/mush.$(MANEXT)
  90. X    cp cmd_help $(LIBDIR)
  91. X    chmod 0644 $(LIBDIR)/cmd_help
  92. X    cp Mushrc $(MRCDIR)/Mushrc
  93. X    chmod 0644 $(MRCDIR)/Mushrc
  94. END_OF_FILE
  95. if test 2051 -ne `wc -c <'mush/makefile.bsd'`; then
  96.     echo shar: \"'mush/makefile.bsd'\" unpacked with wrong size!
  97. fi
  98. # end of 'mush/makefile.bsd'
  99. fi
  100. if test -f 'mush/misc.c' -a "${1}" != "-c" ; then 
  101.   echo shar: Will not clobber existing file \"'mush/misc.c'\"
  102. else
  103. echo shar: Extracting \"'mush/misc.c'\" \(22011 characters\)
  104. sed "s/^X//" >'mush/misc.c' <<'END_OF_FILE'
  105. X/* @(#)misc.c    (c) copyright 10/18/86 (Dan Heller) */
  106. X
  107. X#include "mush.h"
  108. X
  109. X/* check to see if a string describes a message that is within the range of
  110. X * all messages; if invalid, return 0 and print error. else return msg number
  111. X */
  112. Xchk_msg(s)
  113. Xregister char *s;
  114. X{
  115. X    register int n;
  116. X
  117. X    if ((n = atoi(s)) > 0 && n <= msg_cnt)
  118. X    return n;
  119. X    else if (*s == '^' && msg_cnt)
  120. X    return 1;
  121. X    else if (*s == '$' && msg_cnt)
  122. X    return msg_cnt;
  123. X    else if (*s == '.' && msg_cnt)
  124. X    return current_msg+1;
  125. X    print("Invalid message number: %s\n", s);
  126. X    return 0;
  127. X}
  128. X
  129. X/*
  130. X * loop thru all msgs starting with current_msg and find next undeleted and
  131. X * unsaved message.  If the variable "wrap" is set, wrap to the beginning of
  132. X * the message list if we hit the end.  otherwise, stop at the end of the list.
  133. X */
  134. Xnext_msg()
  135. X{
  136. X    register int n = current_msg;
  137. X    register int wrap = !!do_set(set_options, "wrap") ||
  138. X    istool && !do_set(set_options, "show_deleted");
  139. X
  140. X    if (!msg_cnt)
  141. X    return current_msg = 0;
  142. X    for (n++; n != current_msg; n++)
  143. X    if (n == msg_cnt)     /* hit the end, start back at the beginning */
  144. X        if (!wrap)
  145. X        return current_msg;
  146. X        else
  147. X        n = -1; /* increments to 0 in  loop  */
  148. X    else if (isoff(msg[n].m_flags, DELETE) &&
  149. X         isoff(msg[n].m_flags, SAVED))
  150. X        return current_msg = n;
  151. X    return current_msg = 0;
  152. X}
  153. X
  154. X/* since print_help just prints help, always return help() */
  155. Xprint_help(argc, argv)
  156. Xregister char **argv;
  157. X{
  158. X#ifdef SUNTOOL
  159. X    if (istool)
  160. X    return help(0, "general", tool_help);
  161. X#endif /* SUNTOOL */
  162. X
  163. X    if (!argc || !*++argv)
  164. X    return help(0, "general", cmd_help);
  165. X    if (argv[0][0] == '-')
  166. X    return help(0, "help", cmd_help);
  167. X    return help(0, *argv, cmd_help);
  168. X}
  169. X
  170. X/* since this function does not affect messages, return -1 */
  171. X/*ARGSUSED*/
  172. Xhelp(unused, str, file)
  173. Xchar *str, *file;
  174. X{
  175. X    register char    *p, **text = (char **)str;
  176. X    char        buf[BUFSIZ], help_str[32];
  177. X    FILE        *fp;
  178. X
  179. X    /* If no file given, take "str" arg as message to print */
  180. X    if (!file || !*file) {
  181. X#ifdef SUNTOOL
  182. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  183. X    /* SunOS 3.5 doesn't have enough file descriptors */
  184. X    turnon(glob_flags, NEW_FRAME);
  185. X#endif /* SUN_4_0 */
  186. X    strdup(more_prompt, "help");
  187. X#endif /* SUNTOOL */
  188. X    /* use the pager on the args to the function */
  189. X    (void) do_pager(NULL, TRUE);
  190. X    while (*text) {
  191. X        (void) do_pager(*text++, FALSE);
  192. X        if (do_pager("\n", FALSE) == EOF)
  193. X        break;
  194. X    }
  195. X    (void) do_pager(NULL, FALSE);
  196. X    return 0;
  197. X    } else {
  198. X    int d = 0;
  199. X    if ((p = getpath(file, &d)) && d == 0) {
  200. X        if (!(fp = fopen(p, "r"))) {
  201. X        print("Cannot open help file \"%s\".\n", p);
  202. X        return -1;
  203. X        }
  204. X    } else {
  205. X        if (d < 0)
  206. X        print("Cannot open help file \"%s\": %s\n", file, p);
  207. X        else
  208. X        print("Help file \"%s\" is a directory?!?\n", p);
  209. X        return -1;
  210. X    }
  211. X    }
  212. X
  213. X    /* look for %str% in helpfile */
  214. X    (void) sprintf(help_str, "%%%s%%\n", str);
  215. X
  216. X    while (p = fgets(buf, sizeof buf, fp))
  217. X    if (*p == '%' && !strcmp(p, help_str))
  218. X        break;
  219. X    if (!p)
  220. X    print("There is no help found for \"%s\".\n", (char *)str);
  221. X    else {
  222. X#ifdef SUNTOOL
  223. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  224. X    /* SunOS 3.5 doesn't have enough file descriptors */
  225. X    turnon(glob_flags, NEW_FRAME);
  226. X#endif /* SUN_4_0 */
  227. X    strdup(more_prompt, sprintf(buf, "%s help", (char *)str));
  228. X#endif /* SUNTOOL */
  229. X    (void) do_pager(NULL, TRUE);
  230. X    while ((p = fgets(buf, sizeof buf, fp)) && strcmp(p, "%%\n"))
  231. X        if (do_pager(buf, FALSE) == EOF)
  232. X        break;
  233. X    (void) do_pager(NULL, FALSE);
  234. X    }
  235. X    (void) fclose(fp);
  236. X
  237. X    return 0;
  238. X}
  239. X
  240. X/* return -1 on error or number of arguments in argv that were parsed */
  241. Xget_msg_list(argv, list)
  242. Xregister char **argv;
  243. Xchar list[];
  244. X{
  245. X    register char *p2, *p, *end, ch;
  246. X    char buf[BUFSIZ];
  247. X    register int n;
  248. X
  249. X    if (!msg_cnt) {
  250. X    print("No messages.\n");
  251. X    return -1;
  252. X    }
  253. X    if (!argv || !*argv) {
  254. X    if (isoff(glob_flags, IS_PIPE))
  255. X        set_msg_bit(list, current_msg);
  256. X    return 0;
  257. X    }
  258. X    /* first, stuff argv's args into a single char array buffer */
  259. X    (void) argv_to_string(buf, argv);
  260. X    p = buf;
  261. X
  262. X    Debug("get_msg_list: parsing: (%s): ", p);
  263. X    /* find the end of the message list */
  264. X    skipmsglist(0);
  265. X    end = p;
  266. X    while (*end && end != buf && !isspace(*end))
  267. X    --end;
  268. X    ch = *end, *end = '\0'; /* temporarily plug with nul */
  269. X    p = buf; /* reset to the beginning */
  270. X    /*
  271. X     * if do_range returns NULL, an invalid message was specified
  272. X     */
  273. X    if (!(p2 = do_range(p, list))) {
  274. X    *end = ch; /* just in case */
  275. X    return -1;
  276. X    }
  277. X    /*
  278. X     * if p2 == p (and p isn't $ or ^ or .), then no message list was
  279. X     * specified.  set the current message in such cases if we're not piping
  280. X     */
  281. X    if (p2 == p) {
  282. X    if (*p == '$')
  283. X        set_msg_bit(list, msg_cnt-1);
  284. X    else if (*p == '^')
  285. X        set_msg_bit(list, 0);
  286. X    else if (*p == '.' || isoff(glob_flags, IS_PIPE))
  287. X        set_msg_bit(list, current_msg);
  288. X    }
  289. X    for (n = 0; p2 > p && *argv; n++)
  290. X    p2 -= (strlen(*argv++)+1);
  291. X    Debug("parsed %d args\n", n);
  292. X    *end = ch;
  293. X    return n;
  294. X}
  295. X
  296. X/*
  297. X * execute a command from a string.  f'rinstance: "pick -f foobar"
  298. X * The string is made into an argv and then run.  Errors are printed
  299. X * if the command failed to make.
  300. X * NOTES:
  301. X *   NEVER pass straight text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...")
  302. X *   no history is expanded (ignore_bang).
  303. X */
  304. Xcmd_line(buf, list)
  305. Xchar buf[], list[];
  306. X{
  307. X    register char **argv;
  308. X    int argc, ret_val = -1;
  309. X    u_long save_do_pipe = ison(glob_flags, DO_PIPE);
  310. X    u_long save_is_pipe = ison(glob_flags, IS_PIPE);
  311. X    char dummy_list[MAXMSGS_BITS];
  312. X
  313. X    turnoff(glob_flags, DO_PIPE);
  314. X    turnoff(glob_flags, IS_PIPE);
  315. X    if (argv = make_command(buf, TRPL_NULL, &argc))
  316. X    ret_val = do_command(argc, argv, list? list : dummy_list);
  317. X    if (save_do_pipe)
  318. X    turnon(glob_flags, DO_PIPE);
  319. X    else
  320. X    turnoff(glob_flags, DO_PIPE);
  321. X    if (save_is_pipe)
  322. X    turnon(glob_flags, IS_PIPE);
  323. X    else
  324. X    turnoff(glob_flags, IS_PIPE);
  325. X    return ret_val;
  326. X}
  327. X
  328. Xglob_test(s)
  329. Xchar *s;
  330. X{
  331. X    print("%s: glob_flags =", s);
  332. X    if (ison(glob_flags, DO_UPDATE))
  333. X    print_more(" DO_UPDATE");
  334. X    if (ison(glob_flags, REV_VIDEO))
  335. X    print_more(" REV_VIDEO");
  336. X    if (ison(glob_flags, CONT_PRNT))
  337. X    print_more(" CONT_PRNT");
  338. X    if (ison(glob_flags, DO_SHELL))
  339. X    print_more(" DO_SHELL");
  340. X    if (ison(glob_flags, DO_PIPE))
  341. X    print_more(" DO_PIPE");
  342. X    if (ison(glob_flags, IS_PIPE))
  343. X    print_more(" IS_PIPE");
  344. X    if (ison(glob_flags, IGN_SIGS))
  345. X    print_more(" IGN_SIGS");
  346. X    if (ison(glob_flags, IGN_BANG))
  347. X    print_more(" IGN_BANG");
  348. X    if (ison(glob_flags, ECHO_FLAG))
  349. X    print_more(" ECHO_FLAG");
  350. X    if (ison(glob_flags, IS_GETTING))
  351. X    print_more(" IS_GETTING");
  352. X    if (ison(glob_flags, PRE_CURSES))
  353. X    print_more(" PRE_CURSES");
  354. X    if (ison(glob_flags, READ_ONLY))
  355. X    print_more(" READ_ONLY");
  356. X    if (ison(glob_flags, REDIRECT))
  357. X    print_more(" REDIRECT");
  358. X    if (ison(glob_flags, WAS_INTR))
  359. X    print_more(" WAS_INTR");
  360. X    if (ison(glob_flags, WARNING))
  361. X    print_more(" WARNING");
  362. X    if (ison(glob_flags, NEW_MAIL))
  363. X    print_more(" NEW_MAIL");
  364. X    if (ison(glob_flags, CNTD_CMD))
  365. X    print_more(" CNTD_CMD");
  366. X    if (ison(glob_flags, IS_SENDING))
  367. X    print_more(" IS_SENDING");
  368. X    if (ison(glob_flags, MIL_TIME))
  369. X    print_more(" MIL_TIME");
  370. X    if (ison(glob_flags, DATE_RECV))
  371. X    print_more(" DATE_RECV");
  372. X    if (ison(glob_flags, IN_MACRO))
  373. X    print_more(" IN_MACRO");
  374. X    if (ison(glob_flags, LINE_MACRO))
  375. X    print_more(" LINE_MACRO");
  376. X    if (ison(glob_flags, QUOTE_MACRO))
  377. X    print_more(" QUOTE_MACRO");
  378. X    print_more("\n");
  379. X}
  380. X
  381. X/*
  382. X * Change the status flags for messages.
  383. X *    flags +r        add the replied-to flag to the current message.
  384. X *    flags -S 4-7    remove the "saved" status on msgs 4-7
  385. X *    flags P *        preserves all messages.
  386. X * The + implies: add this flag to the current message's flag bits
  387. X * The - implies: delete this flag to the current message's flag bits
  388. X * No + or - implies that the msg's flag bits are set explicitly.
  389. X */
  390. Xmsg_flags(c, v, list)
  391. Xregister char **v, *list;
  392. X{
  393. X    register int    i = 0, modify = 0, had_list = 0;
  394. X    register u_long    newflag = 0;
  395. X    char        sent[32], recv[32];
  396. X
  397. X    while (v && *v && *++v)
  398. X    for (c = 0; v && v[0] && v[0][c]; c++)
  399. X        switch (lower(v[0][c])) {
  400. X        case '?' : return help(0, "msg_flags", cmd_help);
  401. X        case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD);
  402. X        when 'd' : turnon(newflag, DELETE);
  403. X        when 'p' :
  404. X            if (v[0][c] == 'P')
  405. X            turnon(newflag, PRESERVE);
  406. X            else
  407. X            turnon(newflag, PRINTED);
  408. X        when 's' : turnon(newflag, SAVED);
  409. X        when 'u' : turnon(newflag, UNREAD); /* fall thru! */
  410. X        case 'o' : turnon(newflag, OLD);
  411. X        when 'r' :
  412. X            if (v[0][c] == 'R')
  413. X            turnoff(newflag, UNREAD), turnon(newflag, OLD);
  414. X            else
  415. X            turnon(newflag, REPLIED);
  416. X        when 'f' : turnon(newflag, FORWARD);
  417. X        when '+' : modify = 1;
  418. X        when '-' : modify = 2;
  419. X        when '\\' : ; /* skip to the next flag */
  420. X        otherwise:
  421. X            if ((i = get_msg_list(v, list)) <= 0) {
  422. X            print("Unknown flag: %c.  Use flags -? for help\n",
  423. X                v[0][c]);
  424. X            return -1;
  425. X            } else {
  426. X            /* advance argv passed the msg-list */
  427. X            v += i;
  428. X            /* c will get ++'ed, so it should be 0 */
  429. X            c = -1;
  430. X            /* record that we have seen a message list */
  431. X            had_list = 1;
  432. X            }
  433. X        }
  434. X    /* If we haven't got a msglist, use current_msg */
  435. X    if (had_list == 0 && isoff(glob_flags, IS_PIPE))
  436. X    set_msg_bit(list, current_msg);
  437. X
  438. X    for (i = 0; i < msg_cnt; i++) {
  439. X    if (!msg_bit(list, i))
  440. X        continue;
  441. X    else if (!newflag) {
  442. X        wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1,
  443. X        msg[i].m_offset, msg[i].m_lines, msg[i].m_size);
  444. X        if (ison(msg[i].m_flags, UNREAD))
  445. X        wprint(" UNREAD");
  446. X        if (ison(msg[i].m_flags, OLD))
  447. X        wprint(" OLD");
  448. X        if (ison(msg[i].m_flags, DELETE))
  449. X        wprint(" DELETE");
  450. X        if (ison(msg[i].m_flags, PRESERVE))
  451. X        wprint(" PRESERVE");
  452. X        if (ison(msg[i].m_flags, REPLIED))
  453. X        wprint(" REPLIED");
  454. X        if (ison(msg[i].m_flags, SAVED))
  455. X        wprint(" SAVED");
  456. X        if (ison(msg[i].m_flags, PRINTED))
  457. X        wprint(" PRINTED");
  458. X        if (ison(msg[i].m_flags, FORWARD))
  459. X        wprint(" FORWARD");
  460. X        if (ison(msg[i].m_flags, UPDATE_STATUS))
  461. X        wprint(" UPDATE_STATUS");
  462. X        (void) strcpy(sent, date_to_ctime(msg[i].m_date_sent));
  463. X        (void) strcpy(recv, date_to_ctime(msg[i].m_date_recv));
  464. X        wprint("\n\tsent: %s\trecv: %s", sent, recv);
  465. X    } else {
  466. X        if (isoff(glob_flags, READ_ONLY))
  467. X        turnon(glob_flags, DO_UPDATE);
  468. X        switch (modify) {
  469. X        case 0: msg[i].m_flags = newflag;
  470. X        when 1: msg[i].m_flags |= newflag;
  471. X        when 2: msg[i].m_flags &= ~newflag;
  472. X        }
  473. X    }
  474. X    }
  475. X    return 0;
  476. X}
  477. X
  478. X/*
  479. X * Internal pager.  Start the internal pager by passing the name of
  480. X * the pager in buf and passing TRUE as start_pager. If the internal
  481. X * pager is desired, pass NULL as buf.  Continue paging by passing
  482. X * FALSE as start_pager and the buf is the stuff to pass thru to the
  483. X * pager.  End paging by passing NULL as buf and FALSE as start_pager.
  484. X * start_pager actually has a ternary value -- for use by pipe_msg.
  485. X * If the pager can't be used, or is null, we're paging ourselves.
  486. X * Windows does nothing but echo buf to the msg window (this will change).
  487. X * The "buf" passed to the pager should be a line at a time so as to
  488. X * count \n's.  If there is more than one newline, the first one is nulled
  489. X * and the next line done by calling do_pager recursively.  WARNING: because
  490. X * "buf" is changed, it is *illegal* for anyone calling this routine to pass
  491. X * _constant_ strings --they should be strcpy'ed or sprintf'ed into a temp
  492. X * buff before passing to this routine!  Otherwise, ANSI-C compilers will
  493. X * core dump.  This is because constant strings are read-only.
  494. X * Return EOF if pager died, user exited pager, or if user types 'q'
  495. X * at the --more-- prompt for the internal pager.
  496. X *
  497. X * For windows, copy all the info into a tmpfile and set the pager_textsw
  498. X * to that file.  When the pager ends, delete the file -- textsw will
  499. X * continue to read it since it does its own buffering.
  500. X */
  501. Xdo_pager(buf, start_pager)
  502. Xchar *buf;
  503. X{
  504. X    static FILE *pp;
  505. X    static char file[MAXPATHLEN];
  506. X    static int cnt, len;
  507. X    static u_long save_echo_flag;
  508. X#ifdef SUNTOOL
  509. X    static Textsw sw;
  510. X
  511. X    /* pipe_msg will pass -1 for start_pager to avoid this block */
  512. X    if (start_pager > -1 && istool) {
  513. X    if (buf && !start_pager) {
  514. X        if (istool < 2) /* can't use windows yet -- send to stdout */
  515. X        (void) fputs(buf, stdout);
  516. X        else {
  517. X        if (pp)
  518. X            fputs(buf, pp);
  519. X        else
  520. X            textsw_insert(isoff(glob_flags, NEW_FRAME)?
  521. X            pager_textsw : sw, buf, strlen(buf));
  522. X        }
  523. X    } else if (istool >= 2 && start_pager) {
  524. X        Frame text_frame;
  525. X        extern char *more_prompt;
  526. X        char *p;
  527. X
  528. X        timeout_cursors(TRUE);
  529. X        if (ison(glob_flags, NEW_FRAME)) {
  530. X        char *crt_win = do_set(set_options, "crt_win");
  531. X        text_frame = window_create(tool, FRAME,
  532. X            FRAME_SHOW_LABEL,    TRUE,
  533. X            FRAME_LABEL,    more_prompt,
  534. X            WIN_HEIGHT,        l_height()*(crt_win? atoi(crt_win):12),
  535. X            NULL);
  536. X        sw = window_create(text_frame, TEXTSW,
  537. X            TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  538. X            TEXTSW_CLIENT_DATA,        text_frame,
  539. X            NULL);
  540. X        notify_interpose_event_func(sw, scroll_textwin, NOTIFY_SAFE);
  541. X        } else
  542. X        textsw_reset(pager_textsw, 0, 0);
  543. X
  544. X        /* find a free tmpfile */
  545. X        if (!(p = getdir(do_set(set_options, "tmpdir"))))
  546. Xalted:
  547. X        p = ALTERNATE_HOME;
  548. X        {
  549. X        int pid = getpid();
  550. X        do
  551. X            sprintf(file, "%s/..X%d", p, pid++);
  552. X        while (!Access(file, F_OK));
  553. X        }
  554. X        if (!(pp = mask_fopen(file, "w"))) {
  555. X        if (strcmp(p, ALTERNATE_HOME))
  556. X            goto alted;
  557. X        error("Can't create '%s'", tempfile);
  558. X        }
  559. X        return 0;
  560. X    } else if (!buf && !start_pager) { /* pager is done */
  561. X        if (pp)
  562. X        (void) fclose(pp);
  563. X        window_set(isoff(glob_flags, NEW_FRAME)? pager_textsw : sw,
  564. X        TEXTSW_FILE,        file,
  565. X        TEXTSW_READ_ONLY,    TRUE,
  566. X        TEXTSW_UPDATE_SCROLLBAR,
  567. X        NULL);
  568. X        if (ison(glob_flags, NEW_FRAME)) {
  569. X        turnoff(glob_flags, NEW_FRAME);
  570. X        window_set(window_get(sw, TEXTSW_CLIENT_DATA),
  571. X            WIN_SHOW,        TRUE,
  572. X            FRAME_NO_CONFIRM,    TRUE,
  573. X            FRAME_DONE_PROC,    window_destroy,
  574. X            NULL);
  575. X        }
  576. X        if (unlink(file) == -1)
  577. X        error("Cannot unlink %s", file);
  578. X        timeout_cursors(FALSE);
  579. X    }
  580. X    return 0;
  581. X    }
  582. X#endif /* SUNTOOL */
  583. X
  584. X    if (start_pager) {
  585. X    turnon(glob_flags, IGN_SIGS);
  586. X    if (!buf) {
  587. X        /* internal pager */
  588. X        save_echo_flag = ison(glob_flags, ECHO_FLAG);
  589. X        pp = stdout;
  590. X        if (save_echo_flag) {
  591. X        turnoff(glob_flags, ECHO_FLAG);
  592. X        echo_off();
  593. X        }
  594. X    } else {
  595. X        echo_on();
  596. X        if (!(pp = popen(buf, "w")))
  597. X        error(buf);
  598. X    }
  599. X    cnt = len = 0;
  600. X    } else if (!buf) {
  601. X    if (pp && pp != stdout)
  602. X        (void) pclose(pp);
  603. X    pp = NULL_FILE;
  604. X    if (save_echo_flag) {
  605. X        echo_on();
  606. X        turnon(glob_flags, ECHO_FLAG);
  607. X    } else
  608. X        echo_off();
  609. X    turnoff(glob_flags, IGN_SIGS);
  610. X    } else if (pp != stdout)
  611. X    return fputs(buf, pp); /* returns EOF if user exited pager */
  612. X    else {
  613. X    register char c = 0, *cr = index(buf, '\n');
  614. X    len += strlen(buf);
  615. X    if (cr) {
  616. X        int maxlen =
  617. X#ifdef CURSES
  618. X        iscurses ? COLS :
  619. X#endif /* CURSES */
  620. X        80;
  621. X        if (len > maxlen)
  622. X        cnt += len / maxlen;
  623. X        len = 0;
  624. X    }
  625. X    if (cr && (c = *++cr) != '\0')
  626. X        *cr = 0; /* send one line to stdout and prompt for more */
  627. X    (void) fputs(buf, pp);
  628. X    if (cr && (++cnt / (crt-1))) {
  629. X        int n = c_more(NULL);
  630. X        if (n == '\n' || n == '\r')
  631. X        cnt--; /* go line by line */
  632. X        else if (n == CTRL('D') || lower(n) == 'd' || n < 0) {
  633. X        clearerr(stdin);
  634. X        cnt = ((crt-1)/2);
  635. X        } else if (lower(n) == 'q')
  636. X        /* could check if "c" is set, but... see warning above */
  637. X        return EOF;
  638. X        else
  639. X        cnt = 1;
  640. X    }
  641. X    if (c) {
  642. X        *cr = c;
  643. X        return do_pager(cr, FALSE);
  644. X    }
  645. X    }
  646. X    return 0;
  647. X}
  648. X
  649. X/* curses based "more" like option */
  650. Xc_more(p)
  651. Xregister char *p;
  652. X{
  653. X    register int c;
  654. X
  655. X    if (!p)
  656. X    p = "--more--";
  657. X    print_more(p);
  658. X    
  659. X    while ((c = getchar()) >= 0 && c != CTRL('D') && !isspace(c) &&
  660. X       c != '\n' && c != '\r' && lower(c) != 'q' && lower(c) != 'd')
  661. X    bell();
  662. X    if (ison(glob_flags, ECHO_FLAG) && c != '\n' && c != '\r')
  663. X    while (getchar() != '\n');
  664. X    (void) printf("\r%*c\r", strlen(p), ' '); /* remove the prompt */
  665. X    (void) fflush(stdout);
  666. X    return c;
  667. X}
  668. X
  669. X/*
  670. X * Your "signature" is of the type:
  671. X *    file_or_path
  672. X *    $variable
  673. X *    \ literal string preceded by a backslash.
  674. X * The variable will be expanded into its string value.
  675. X * To sign the letter, the list of addresses is passed to this routine
  676. X * (separated by whitespace and/or commas).  No comment fields!
  677. X *
  678. X * If "autosign2" is set, then it must be of the form:
  679. X *    autosign2 = "*user user !host !some!path @dom.ain: ~/.sign2"
  680. X *
  681. X * The colon terminates the user/host lists from the "signature" to the right.
  682. X *
  683. X * Whitespace or commas separate tokens.  If everyone on the list exists in
  684. X * the autosign2 list, the alternate signature is used. In case of syntax
  685. X * error, the alternate signature is used without checks (e.g. if the colon
  686. X * is missing).  The alternate signature == null is the same as not signing
  687. X * the letter. An empty list forces signature2.
  688. X *
  689. X * If autosign2 is not set at all, then autosign is checked and used.
  690. X * autosign = <signature>
  691. X */
  692. Xvoid
  693. Xsign_letter(list, flags, fp)
  694. Xregister char *list; /* list of addresses -- no comment fields */
  695. Xu_long flags;
  696. XFILE *fp;
  697. X{
  698. X    char buf[MAXPATHLEN], *signature;
  699. X    register char *p = NULL;
  700. X    FILE     *pp2;
  701. X    int     lines = 0, noisy;
  702. X
  703. X    if (!list)
  704. X    return;
  705. X    while (isspace(*list))
  706. X    list++;
  707. X    if (!*list)
  708. X    return;
  709. X    if (ison(flags, SIGN)) {
  710. X    noisy = !chk_option("quiet", "autosign");
  711. X    if (!(p = do_set(set_options, "autosign2")))
  712. X        buf[0] = 0;
  713. X    else {
  714. X        if (!(signature = index(p, ':')))
  715. X        (void) strcpy(buf, p); /* No colon; use entire string as sig */
  716. X        else {
  717. X        int ret_val = 0;
  718. X        *signature = 0;
  719. X        /* p now points to a list of addresses and p2 points to the
  720. X         * signature format to use. Check that each address in the list
  721. X         * provided (parameter) matches the "addrs" in autosign2.
  722. X         */
  723. X        skipspaces(0);
  724. X        if (!*p)
  725. X            /* autosign2 = " : <signature>"  send to all recipients */
  726. X            ret_val = 1;
  727. X        else if (p = alias_to_address(p)) {
  728. X            rm_cmts_in_addr(p);
  729. X            ret_val = compare_addrs(list, p, NULL);
  730. X        }
  731. X        *signature++ = ':'; /* must reset first! */
  732. X        buf[0] = 0;
  733. X        if (ret_val) {
  734. X            while (isspace(*signature))
  735. X            signature++;
  736. X            /* Null signatures don't sign anything. */
  737. X            if (!*strcpy(buf, signature))
  738. X            return;
  739. X        }
  740. X        }
  741. X    }
  742. X    if (!buf[0]) {
  743. X        if (!(p = do_set(set_options, "autosign")) || !*p) {
  744. X        char *home;
  745. X        if (!(home = do_set(set_options, "home")) || !*home)
  746. X            home = ALTERNATE_HOME;
  747. X        (void) sprintf(buf, "%s/%s", home, SIGNATURE);
  748. X        } else
  749. X        (void) strcpy(buf, p);
  750. X        if (noisy)
  751. X        wprint("Signing letter... ");
  752. X    } else if (noisy)
  753. X        wprint("Using alternate signature... ");
  754. X    (void) fseek(fp, 0L, 2); /* guarantee position at end of file */
  755. X    (void) fputc('\n', fp);
  756. X    (void) fflush(fp);
  757. X    if (*buf == '$')
  758. X        if (!(p = do_set(set_options, buf)))
  759. X        wprint("(%s isn't set -- letter not signed)\n", buf);
  760. X        else {
  761. X        putstring(p+1, fp);
  762. X        if (noisy)
  763. X            wprint("\n");
  764. X        }
  765. X    else if (*buf == '\\') {
  766. X        putstring(buf, fp);
  767. X        if (noisy)
  768. X        wprint("\n");
  769. X    } else if (*buf == '[') {
  770. X        char *rbr = index(buf, ']');
  771. X        if (rbr)
  772. X        *rbr = 0;
  773. X        putstring(buf + 1, fp);
  774. X        if (noisy)
  775. X        wprint("\n");
  776. X    } else if (*buf == '|' || *buf == '!') {
  777. X        (void) strcat(buf, " ");
  778. X        (void) strcat(buf, list);
  779. X        if (!(pp2 = popen(buf+1, "r")))
  780. X        error(buf+1);
  781. X        else {
  782. X        turnon(glob_flags, IGN_SIGS);
  783. X        while (fgets(buf, sizeof(buf), pp2))
  784. X            (void) fputs(buf, fp), lines++;
  785. X        (void) pclose(pp2);
  786. X        (void) fflush(fp);
  787. X        turnoff(glob_flags, IGN_SIGS);
  788. X        if (noisy)
  789. X            wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  790. X        }
  791. X    } else {
  792. X        /* precede _file_ signatures ONLY with "-- \n" */
  793. X        (void) fputs("-- \n", fp);
  794. X        (void) fflush(fp);
  795. X        (void) file_to_fp(buf, fp, "r");
  796. X    }
  797. X    }
  798. X
  799. X    (void) fflush(stdout); /* for sys-v and older xenix */
  800. X
  801. X    /* if fortune is set, check to see if fortunates is set. If so,
  802. X     * check to see if all the recipient are on the fortunates list.
  803. X     */
  804. X    if (ison(flags, DO_FORTUNE)) {
  805. X    noisy = !chk_option("quiet", "fortune");
  806. X    if (p = do_set(set_options, "fortunates")) {
  807. X        if (!(p = alias_to_address(p)))
  808. X        return; /* no reason to hang around */
  809. X        rm_cmts_in_addr(p);
  810. X        if (!compare_addrs(list, p, buf)) {
  811. X        if (noisy) {
  812. X            wprint("\"fortunates\" does not contain \"%s\".\n", buf);
  813. X            wprint("No fortune added.\n");
  814. X        }
  815. X        return;
  816. X        }
  817. X    }
  818. X    if (noisy)
  819. X        wprint("You may be fortunate... ");
  820. X    if ((p = do_set(set_options, "fortune")) && *p == '/')
  821. X        (void) strcpy(buf, p);
  822. X    else
  823. X        (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
  824. X    if (!(pp2 = popen(buf, "r")))
  825. X        error(buf);
  826. X    else {
  827. X        turnon(glob_flags, IGN_SIGS);
  828. X        (void) fseek(fp, 0L, 2); /* go to end of file */
  829. X        while (fgets(buf, sizeof(buf), pp2))
  830. X        (void) fputs(buf, fp), lines++;
  831. X        (void) pclose(pp2);
  832. X        turnoff(glob_flags, IGN_SIGS);
  833. X        (void) fflush(fp);
  834. X        if (noisy)
  835. X        wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  836. X    }
  837. X    }
  838. X    (void) fflush(stdout); /* for sys-v and older xenix */
  839. X}
  840. X
  841. X
  842. X/* return -1 since function doesn't affect messages */
  843. Xcheck_flags(flags)
  844. Xu_long flags;
  845. X{
  846. X    print_more(" ");
  847. X    if (ison(flags, VERBOSE))
  848. X    print_more("VERBOSE ");
  849. X    if (ison(flags, INCLUDE))
  850. X    print_more("INCLUDE ");
  851. X    if (ison(flags, INCLUDE_H))
  852. X    print_more("INCLUDE_H ");
  853. X    if (ison(flags, EDIT))
  854. X    print_more("EDIT ");
  855. X    if (ison(flags, SIGN))
  856. X    print_more("SIGN ");
  857. X    if (ison(flags, DO_FORTUNE))
  858. X    print_more("DO_FORTUNE ");
  859. X    if (ison(flags, NO_HEADER))
  860. X    print_more("NO_HEADER ");
  861. X    if (ison(flags, DELETE))
  862. X    print_more("DELETE ");
  863. X    if (ison(flags, OLD))
  864. X    print_more("OLD ");
  865. X    if (ison(flags, UNREAD))
  866. X    print_more("UNREAD ");
  867. X    if (ison(flags, UPDATE_STATUS))
  868. X    print_more("UPDATE_STATUS ");
  869. X    if (ison(flags, NO_PAGE))
  870. X    print_more("NO_PAGE ");
  871. X    if (ison(flags, INDENT))
  872. X    print_more("INDENT ");
  873. X    if (ison(flags, NO_IGNORE))
  874. X    print_more("NO_IGNORE ");
  875. X    if (ison(flags, PRESERVE))
  876. X    print_more("PRESERVE ");
  877. X    print_more("\n");
  878. X    return -1;
  879. X}
  880. END_OF_FILE
  881. if test 22011 -ne `wc -c <'mush/misc.c'`; then
  882.     echo shar: \"'mush/misc.c'\" unpacked with wrong size!
  883. fi
  884. # end of 'mush/misc.c'
  885. fi
  886. if test -f 'mush/msgs.c' -a "${1}" != "-c" ; then 
  887.   echo shar: Will not clobber existing file \"'mush/msgs.c'\"
  888. else
  889. echo shar: Extracting \"'mush/msgs.c'\" \(27478 characters\)
  890. sed "s/^X//" >'mush/msgs.c' <<'END_OF_FILE'
  891. X/* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  892. X
  893. X#include "mush.h"
  894. X
  895. Xvoid
  896. Xdisplay_msg(n, flg)
  897. Xregister int n;
  898. Xu_long flg;
  899. X{
  900. X    char buf[32], *pager = NULL;
  901. X
  902. X    if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
  903. X    print("Message %d deleted; ", n+1);
  904. X#ifdef SUNTOOL
  905. X    if (istool)
  906. X        wprint("Select UNDELETE to read.\n");
  907. X    else
  908. X#endif /* SUNTOOL */
  909. X    if (iscurses)
  910. X        print_more("Type 'u' to undelete.");
  911. X    else
  912. X        wprint("Type 'undelete %d' to undelete\n", n+1);
  913. X    return;
  914. X    }
  915. X    set_isread(n);
  916. X    if (ison(flg, M_TOP)) {
  917. X    turnon(flg, NO_HEADER);
  918. X    print("Top of "), turnon(glob_flags, CONT_PRNT);
  919. X    }
  920. X
  921. X#ifdef MSG_SEPARATOR
  922. X    turnon(flg, NO_SEPARATOR);
  923. X#endif /* MMDF */
  924. X    if (!istool && isoff(flg, NO_PAGE) &&
  925. X        crt < msg[n].m_lines && isoff(flg, M_TOP)) {
  926. X    if (!(pager = do_set(set_options, "pager")))
  927. X        pager = DEF_PAGER;
  928. X    if (!*pager || !strcmp(pager, "internal"))
  929. X        pager = NULL; /* default to internal pager if pager set to "" */
  930. X    }
  931. X    (void) do_pager(pager, TRUE); /* start pager */
  932. X    (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
  933. X             n+1, msg[n].m_lines), FALSE);
  934. X    (void) copy_msg(n, NULL_FILE, flg, NULL);
  935. X    (void) do_pager(NULL, FALSE); /* end pager */
  936. X}
  937. X
  938. X/*
  939. X * copy message 'n' to file "fp" according to various flag arguments
  940. X * return number of lines copied or -1 if system error on fputs.
  941. X * If "fp" is null, send to internal pager.  This can only happen from
  942. X * display_msg above.
  943. X */
  944. Xcopy_msg(n, fp, flags, pattern)
  945. Xregister int n;
  946. Xregister FILE *fp;
  947. Xu_long flags;
  948. Xchar *pattern;
  949. X{
  950. X    register int  ignoring = 0, lines = 0;
  951. X    register char *indent_str, *p, *end_pat = NULL;
  952. X    int          on_hdr = 1, top, squeeze = 0;
  953. X    long      still_more = 0;
  954. X    int          pat_len, pat_seek;
  955. X    char       line[BUFSIZ], *show_hdrs = NULL;
  956. X
  957. X    if (ison(flags, M_TOP)) {
  958. X    p = do_set(set_options, "toplines");
  959. X    top = (p)? atoi(p) : crt;
  960. X    }
  961. X    /* When updating to a folder, always write all headers! */
  962. X    if (ison(flags, UPDATE_STATUS))
  963. X    turnon(flags, NO_IGNORE);
  964. X    else if (ison(flags, NO_IGNORE) &&
  965. X        (p = do_set(set_options, "alwaysignore")) && !*p)
  966. X    turnoff(flags, NO_IGNORE);    /* preserve historic behavior */
  967. X    if (isoff(flags, NO_IGNORE)) {
  968. X    if (do_set(set_options, "squeeze"))
  969. X        squeeze = 1;
  970. X    show_hdrs = do_set(set_options, "show_hdrs");
  971. X    }
  972. X    if (pattern && *pattern == '/' && (end_pat = index(pattern+1, '/'))) {
  973. X    if (end_pat[1] == ',') {
  974. X        pattern++;
  975. X        *end_pat++ = 0;
  976. X    } else
  977. X        end_pat = NULL;
  978. X    }
  979. X    pat_len = pattern? strlen(pattern) : 0;
  980. X    pat_seek = !!pat_len;
  981. X
  982. X#ifdef SUNTOOL
  983. X    xfree(more_prompt), more_prompt = NULL;
  984. X#endif /* SUNTOOL */
  985. X
  986. X    if (ison(flags, INDENT)) {
  987. X    if ((indent_str = do_set(set_options, "pre_indent_str"))) {
  988. X        fputs(format_hdr(n, indent_str, FALSE) + 9, fp); /* magic 9 !! */
  989. X        fputc('\n', fp);
  990. X    }
  991. X    if (!(indent_str = do_set(set_options, "indent_str")))
  992. X        indent_str = DEF_INDENT_STR;
  993. X    }
  994. X    /* "line" used as dummy here, since 0 bytes read */
  995. X    if (!msg_get(n, line, 0)) {
  996. X    error("Unable to find msg %d", n+1);
  997. X    return -1;
  998. X    }
  999. X    while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
  1000. X    still_more += strlen(line);
  1001. X#ifdef MSG_SEPARATOR
  1002. X    if (ison(flags, NO_SEPARATOR)) {
  1003. X#ifdef MMDF
  1004. X        if (!strncmp(line, MSG_SEPARATOR, 4))
  1005. X#else /* !MMDF */
  1006. X        if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  1007. X#endif /* MMDF */
  1008. X        continue;
  1009. X    }
  1010. X#endif /* MMDF */
  1011. X    /*
  1012. X     * If squeeze is one, all blanks lines squeeze down to one blank line.
  1013. X     * If squeeze is two, squeezing is in progress so wait for the next \n.
  1014. X     */
  1015. X    if (*line == '\n') {
  1016. X        if (on_hdr) {  /* blank line -- end of header */
  1017. X        on_hdr = 0;
  1018. X        if (ison(flags, NO_HEADER))
  1019. X            continue;
  1020. X        }
  1021. X        if (squeeze > 1 || pat_len && pat_seek)
  1022. X        continue;
  1023. X        else if (squeeze)
  1024. X        squeeze = 2;
  1025. X    } else {
  1026. X        if (squeeze > 1)
  1027. X        squeeze = 1;
  1028. X        if (pat_len && (!on_hdr || isoff(flags, NO_HEADER))) {
  1029. X        /* If we're looking for a pattern for mush-pipe, then
  1030. X         * continue if this line doesn't match the pattern.
  1031. X         */
  1032. X        if (pat_len == 0)
  1033. X            continue;
  1034. X        Debug("Seeking (%s) in (%s)", pattern, line);
  1035. X        if (strncmp(line, pattern, pat_len)) {
  1036. X            if (pat_seek)
  1037. X            continue;
  1038. X        } else if (end_pat && *end_pat++ == ',') {
  1039. X            pattern = end_pat;
  1040. X            if (*pattern == '/') {
  1041. X            pattern++;
  1042. X            if (end_pat = index(pattern, '/'))
  1043. X                *end_pat++ = 0;
  1044. X            }
  1045. X            pat_len = pattern? strlen(pattern) : 0;
  1046. X            pat_seek = !pat_seek;
  1047. X        } else {
  1048. X            pat_len = 0;
  1049. X            pat_seek = !pat_seek;
  1050. X        }
  1051. X        }
  1052. X    }
  1053. X
  1054. X    if (ison(flags, UPDATE_STATUS))
  1055. X        if (!strncmp(line, "Status:", 7))
  1056. X        continue; /* ignore this and other "Status" lines */
  1057. X        else if (!on_hdr) {
  1058. X        /* preserve NEW/UNREAD status on preserved messages */
  1059. X        p = line;
  1060. X        p += Strcpy(p, "Status: O");
  1061. X        if (isoff(msg[n].m_flags, UNREAD) &&
  1062. X            isoff(msg[n].m_flags, PRESERVE))
  1063. X            *p++ = 'R';
  1064. X        if (ison(msg[n].m_flags, SAVED))
  1065. X            *p++ = 'S';
  1066. X        if (ison(msg[n].m_flags, REPLIED))
  1067. X            *p++ = 'r';
  1068. X        if (ison(msg[n].m_flags, PRINTED))
  1069. X            *p++ = 'p';
  1070. X        if (ison(msg[n].m_flags, FORWARD))
  1071. X            *p++ = 'f';
  1072. X        *p++ = '\n', *p = 0;
  1073. X        (void) fputs(line, fp);
  1074. X        line[0] = '\n', line[1] = '\0';
  1075. X        turnoff(flags, UPDATE_STATUS);
  1076. X        }
  1077. X    if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
  1078. X        p = any(line, " \t:");
  1079. X        if (!p)
  1080. X        ignoring = 0, on_hdr = 0;
  1081. X        else if (ignoring)
  1082. X        if (*p != ':') {
  1083. X            Debug("Ignoring: %s", line);
  1084. X            continue;
  1085. X        } else
  1086. X            ignoring = 0;
  1087. X        if (p && *p == ':') {
  1088. X        *p = 0;
  1089. X        ignoring = 0;
  1090. X        if (ison(flags, FORWARD)) {
  1091. X            if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
  1092. X            ignoring = 1;
  1093. X        } else if (show_hdrs) {
  1094. X            if (!chk_two_lists(line, show_hdrs, ":, \t"))
  1095. X            ignoring = 1;
  1096. X        } else {
  1097. X            register struct options *opts;
  1098. X            for (opts = ignore_hdr; opts; opts = opts->next)
  1099. X            if (!lcase_strncmp(opts->option, line, -1)) {
  1100. X                ignoring = 1;
  1101. X                break;
  1102. X            }
  1103. X        }
  1104. X        *p = ':';
  1105. X        if (ignoring) {
  1106. X            Debug("Ignoring: %s", line);
  1107. X            continue;
  1108. X        }
  1109. X        }
  1110. X    }
  1111. X    if (!on_hdr && ison(flags, M_TOP) && !--top)
  1112. X        break;
  1113. X    if (!on_hdr && (still_more < msg[n].m_size || line[0] != '\n') ||
  1114. X        isoff(flags, NO_HEADER)) {
  1115. X        /* note that function returns the number of lines */
  1116. X        lines++;
  1117. X        if (ison(flags, INDENT))
  1118. X        (void) fputs(indent_str, fp);
  1119. X        if (!fp) {
  1120. X        if (do_pager(line, FALSE) == EOF)
  1121. X            return -1;
  1122. X        } else if (fputs(line, fp) == EOF)
  1123. X        /* Pipe broken, out of file space, etc */
  1124. X        return -1;
  1125. X    }
  1126. X    if (pat_seek && !pat_len)
  1127. X        break; /* Skip the rest */
  1128. X    }
  1129. X    if (ison(flags, INDENT) &&
  1130. X    (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
  1131. X    (void) fprintf(fp, "%s\n", format_hdr(n, indent_str, FALSE)+9);
  1132. X    }
  1133. X    if (fp && fflush(fp) == EOF)
  1134. X    return -1;    /* Write failure? */
  1135. X    return lines;
  1136. X}
  1137. X
  1138. X/*
  1139. X * copy tempfile back to folder.
  1140. X * Return 1 on success, 0 on failure.
  1141. X */
  1142. Xcopyback(prompt)
  1143. Xchar *prompt;
  1144. X{
  1145. X    register int    i = 0, held = 0, saved = 0;
  1146. X    register u_long    flg = 0;
  1147. X    register FILE    *mbox = NULL_FILE, *mail_fp = NULL_FILE;
  1148. X#ifdef SYSV
  1149. X    FILE         *save_mail_fp = NULL_FILE;
  1150. X#endif /* SYSV */
  1151. X    char        *mbox_file, action = 0;
  1152. X    int         hold = 0, delete_it = 0, dont_unlink = FALSE;
  1153. X    int            isspool, keepsave, write_err = FALSE;
  1154. X    static int        first = 1;
  1155. X
  1156. X    /*
  1157. X     * if there is new mail in this folder, the user is notified and
  1158. X     * prompted if he really wants to update the folder.  He's either
  1159. X     * quitting or changing folders, so let him read the new mail first.
  1160. X     */
  1161. X    if (!first && mail_size()) {
  1162. Xlost_lock:
  1163. X    if (get_new_mail(TRUE) && prompt && isoff(glob_flags, REDIRECT)
  1164. X        && show_new_mail()) {
  1165. X        char buf[80];
  1166. X        if (iscurses)
  1167. X        putchar('\n'), turnon(glob_flags, CNTD_CMD);
  1168. X        if (!istool)
  1169. X        print("%s [n] ", prompt);
  1170. X        buf[0] = 0;
  1171. X#ifdef SUNTOOL
  1172. X        if (istool) {
  1173. X        (void) sprintf(buf, "New mail -- %s", prompt);
  1174. X        if (ask(buf) != TRUE)
  1175. X            return 0;
  1176. X        } else
  1177. X#endif /* SUNTOOL */
  1178. X        if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  1179. X            return 0;
  1180. X    }
  1181. X    }
  1182. X    first = 0;
  1183. X
  1184. X    /* If the user hasn't changed anything, just return true */
  1185. X    if (isoff(glob_flags, DO_UPDATE))
  1186. X    return 1;
  1187. X    if (ison(glob_flags, READ_ONLY)) {
  1188. X    print("Unable to update %s: read only\n", mailfile);
  1189. X    return 0; /* user should use "exit" instead of "quit". */
  1190. X    }
  1191. X    if (!msg_cnt) /* prevent unnecessary overwrite */
  1192. X    return 1;
  1193. X
  1194. X#ifdef SUNTOOL
  1195. X    if (istool) {
  1196. X    (void) notify_set_itimer_func(tool, do_check,
  1197. X        ITIMER_REAL, (struct itimerval *) 0, (struct itimerval *) 0);
  1198. X    }
  1199. X#endif /* SUNTOOL */
  1200. X
  1201. X    /* We can't lock a file unless we have an fd, but "w+" will zero
  1202. X     * the file.  If the lock later failed for any reason (possible
  1203. X     * race condition with an MTA), we would lose all current mail.
  1204. X     * So, open read/write (if possible) and truncate later.
  1205. X     */
  1206. X    if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
  1207. X    error("WARNING: unable to lock %s -- update aborted", mailfile);
  1208. X#ifdef SUNTOOL
  1209. X    write_err = 1;    /* forces return 0; below */
  1210. X    goto resume_timer;    /* blecch */
  1211. X#else /* !SUNTOOL */
  1212. X    return 0;
  1213. X#endif /* SUNTOOL */
  1214. X    }
  1215. X    /* Make sure no mail arrived between the last check and when we
  1216. X     * got the lock.  If it did, release the lock and try again.
  1217. X     */
  1218. X    if (mail_size()) {
  1219. X    (void) close_lock(mailfile, mail_fp);
  1220. X    goto lost_lock;
  1221. X    }
  1222. X
  1223. X    /* open mbox if: "autodelete" AND "hold" are NOT set. */
  1224. X    if (!strcmp(mailfile, spoolfile)
  1225. X        && !(delete_it = !!do_set(set_options, "autodelete"))
  1226. X        && !(hold = !!do_set(set_options, "hold"))) {
  1227. X    register char *p;
  1228. X    int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  1229. X
  1230. X    if (!(p = do_set(set_options, "mbox")))
  1231. X        p = DEF_MBOX;
  1232. X    mbox_file = getpath(p, &x); /* static data -- copy? */
  1233. X    if (x) {
  1234. X        if (x > 0)
  1235. X        print("%s is a directory.\n", mbox_file);
  1236. X        else
  1237. X        print("Unable to open %s: %s\n", p, mbox_file);
  1238. X        mbox = NULL_FILE;
  1239. X    } else {
  1240. X        if (Access(mbox_file, F_OK) == -1) /* does it exist? */
  1241. X        mbox = lock_fopen(mbox_file, "w");
  1242. X        else
  1243. X        mbox = lock_fopen(mbox_file, "a");
  1244. X        if (!mbox)
  1245. X        error("Unable to write to %s", mbox_file);
  1246. X    }
  1247. X    }
  1248. X
  1249. X    /* ignore signals before truncating */
  1250. X    turnon(glob_flags, IGN_SIGS);
  1251. X#ifdef SYSV
  1252. X    /* SysV can't truncate a file in the middle, so we can't just
  1253. X     * write to mail_fp and close.  Instead, we save the mail_fp
  1254. X     * and reopen for writing, ignoring our own lock.  After updating,
  1255. X     * we can safely fclose both file pointers.
  1256. X     */
  1257. X    save_mail_fp = mail_fp;
  1258. X    /* This could fail if we run out of file descriptors */
  1259. X    if (!(mail_fp = fopen(mailfile, "w"))) {
  1260. X    error("WARNING: unable to reopen %s for update", mailfile);
  1261. X    if (save_mail_fp)
  1262. X        (void) close_lock(mailfile, save_mail_fp);
  1263. X    if (mbox)
  1264. X        (void) close_lock(mbox_file, mbox);
  1265. X    turnoff(glob_flags, IGN_SIGS);
  1266. X    return 0;
  1267. X    }
  1268. X#endif /* SYSV */
  1269. X
  1270. X    print("Updating \"%s\"", mailfile);
  1271. X
  1272. X    turnon(flg, UPDATE_STATUS);
  1273. X
  1274. X    keepsave = !!do_set(set_options, "keepsave");
  1275. X    isspool = !strcmp(mailfile, spoolfile);
  1276. X
  1277. X    for (i = 0; i < msg_cnt; i++) {
  1278. X    /* Maintain the current message across update; if this turns out
  1279. X     * to be unnecessary (changing folders), folder() will reset it.
  1280. X     */
  1281. X    if (current_msg == i)
  1282. X        current_msg = held;
  1283. X    /* Check to see if message is marked for deletion or, if read and not
  1284. X     * preserved, delete it if autodelete is set.  Otherwise, if hold is
  1285. X     * set save the message in the spool file.  If all fails, save in mbox.
  1286. X     */
  1287. X    if (ison(msg[i].m_flags, DELETE)
  1288. X    ||  ison(msg[i].m_flags, SAVED) && !keepsave &&
  1289. X        isoff(msg[i].m_flags, PRESERVE) && isspool
  1290. X    ||  isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  1291. X        && delete_it) {
  1292. X        Debug("%s %d",
  1293. X        (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  1294. X        continue;
  1295. X    } else if (ison(msg[i].m_flags, UNREAD) ||
  1296. X         ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
  1297. X        Debug("%s %d",
  1298. X        (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  1299. X        if (copy_msg(i, mail_fp, flg, NULL) == -1) {
  1300. X        error("WARNING: unable to write back to spool");
  1301. X        print_more("ALL mail left in %s\n", tempfile);
  1302. X        print_more("Spool mailbox may be corrupted.\n");
  1303. X        dont_unlink = TRUE;
  1304. X        write_err = TRUE;
  1305. X        break;
  1306. X        }
  1307. X        held++;
  1308. X    } else if (isspool) {   /* copy back to mbox */
  1309. X        if (copy_msg(i, mbox, flg, NULL) == -1) {
  1310. X        error("WARNING: unable to write to mbox");
  1311. X        print_more("Unresolved mail left in %s\n", tempfile);
  1312. X        dont_unlink = TRUE;
  1313. X        write_err = TRUE;
  1314. X        break;
  1315. X        }
  1316. X        saved++;
  1317. X        Debug("%s %d",
  1318. X        (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  1319. X    }
  1320. X    }
  1321. X    if (write_err)
  1322. X    current_msg = 0;
  1323. X    else if (current_msg == held)
  1324. X    current_msg--;    /* Don't point to a message that got deleted */
  1325. X    Debug("\n%s", mailfile);
  1326. X
  1327. X#ifdef SYSV
  1328. X    /* Close the write file pointer first */
  1329. X    (void) fclose(mail_fp);
  1330. X    mail_fp = save_mail_fp;
  1331. X#else /* !SYSV */
  1332. X    /* Truncate the file at the end of what we just wrote.
  1333. X     * If you aren't SYSV and you still can't ftruncate(),
  1334. X     * you're out of luck?
  1335. X     */
  1336. X    (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
  1337. X#endif /* SYSV */
  1338. X
  1339. X    /* some users like to have zero length folders for frequent usage */
  1340. X    if (mbox && close_lock(mbox_file, mbox) == EOF) {
  1341. X    error("WARNING: unable to close mbox");
  1342. X    print_more("Unresolved mail left in %s\n", tempfile);
  1343. X    dont_unlink = TRUE;
  1344. X    write_err = TRUE;
  1345. X    }
  1346. X    if (held) {
  1347. X    print_more(": saved %d message%s\n", held, (held==1)? NO_STRING: "s");
  1348. X    } else
  1349. X#ifdef HOMEMAIL
  1350. X    if (!dont_unlink && !do_set(set_options, "save_empty"))
  1351. X#else /* HOMEMAIL */
  1352. X    if (strcmp(mailfile, spoolfile) && !dont_unlink &&
  1353. X    !do_set(set_options, "save_empty"))
  1354. X#endif /* HOMEMAIL */
  1355. X    if (unlink(mailfile))
  1356. X        turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  1357. X    else {
  1358. X        print_more(": removed\n");
  1359. X        held = -1;
  1360. X    }
  1361. X    else
  1362. X    print_more(": empty\n");
  1363. X    if (saved)
  1364. X    print("saved %d message%s in %s\n",
  1365. X                saved,(saved==1)? NO_STRING:"s", mbox_file);
  1366. X
  1367. X    if (held > 0) {
  1368. X    /* Reset the access time of the spool file to prevent
  1369. X     * bogus "new mail" messages from the shell.
  1370. X     */
  1371. X    long times[2];
  1372. X    (void) fflush(mail_fp); /* just in case */
  1373. X    times[1] = time(×[0]) - (long)2;
  1374. X    if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
  1375. X        error("utime");
  1376. X    }
  1377. X
  1378. X    if (close_lock(mailfile, mail_fp) == EOF) {
  1379. X    error("WARNING: unable to close spool");
  1380. X    print_more("ALL mail left in %s\n", tempfile);
  1381. X    print_more("Spool mailbox may be corrupted.\n");
  1382. X    write_err = TRUE;
  1383. X    }
  1384. X
  1385. X#ifdef SUNTOOL
  1386. X    if (istool) {
  1387. Xresume_timer:
  1388. X    mail_timer.it_value.tv_sec = time_out;
  1389. X    mail_timer.it_interval.tv_sec = time_out;
  1390. X    (void) notify_set_itimer_func(tool, do_check,
  1391. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  1392. X    }
  1393. X#endif /* SUNTOOL */
  1394. X
  1395. X    turnoff(glob_flags, IGN_SIGS);
  1396. X
  1397. X    /* Return nonzero for success, -1 if file removed */
  1398. X    if (write_err)
  1399. X    return 0;
  1400. X    else if (held < 0)
  1401. X    return -1;
  1402. X    else
  1403. X    return 1;
  1404. X}
  1405. X
  1406. X/*
  1407. X * check the sizes of the current folder (file) and the spool file.
  1408. X * spool_size is the size in bytes of the user's main mailbox.
  1409. X * last_size is the size of the _current_ folder the last time we checked.
  1410. X * return true if the current folder has new mail.  check_new_mail() checks
  1411. X * for new mail in the system mailbox since it checks against last_spool_size.
  1412. X */
  1413. Xmail_size()
  1414. X{
  1415. X    struct stat buf;
  1416. X
  1417. X    if (!stat(spoolfile, &buf))
  1418. X    spool_size = buf.st_size;
  1419. X    else if (!strcmp(mailfile, spoolfile))
  1420. X    return 0;
  1421. X    if (!is_shell || ison(glob_flags, IS_SENDING))
  1422. X    return 0;
  1423. X    if (strcmp(mailfile, spoolfile) && stat(mailfile, &buf)) {
  1424. X    if (errno != ENOENT)
  1425. X        error("Unable to stat %s", mailfile);
  1426. X    return 0;
  1427. X    }
  1428. X    if (buf.st_size != last_size) {
  1429. X    last_size = buf.st_size;
  1430. X    return 1;
  1431. X    }
  1432. X    return 0;
  1433. X}
  1434. X
  1435. Xstatic
  1436. Xstruct mailstat {
  1437. X    int new, unread, deleted;
  1438. X} mail_stat;
  1439. X
  1440. Xvoid
  1441. Xmail_status(as_prompt)
  1442. X{
  1443. X    char buf[MAXPATHLEN];
  1444. X    register int cnt;
  1445. X
  1446. X    mail_stat.new = mail_stat.unread = mail_stat.deleted = 0;
  1447. X
  1448. X    for (cnt = 0; cnt < msg_cnt; cnt++) {
  1449. X    if (ison(msg[cnt].m_flags, UNREAD))
  1450. X        mail_stat.unread++;
  1451. X    if (ison(msg[cnt].m_flags, DELETE))
  1452. X        mail_stat.deleted++;
  1453. X    if (isoff(msg[cnt].m_flags, OLD))
  1454. X        mail_stat.new++;
  1455. X    }
  1456. X    if (as_prompt) {
  1457. X    /* use %s in case prompt has any %'s in it */
  1458. X    print("%s", format_prompt(current_msg, prompt));
  1459. X    return;
  1460. X    }
  1461. X    (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  1462. X    trim_filename(mailfile),
  1463. X    ison(glob_flags, READ_ONLY)? " [read only]" : "",
  1464. X    msg_cnt, (msg_cnt != 1)? "s": NO_STRING,
  1465. X    mail_stat.new, mail_stat.unread);
  1466. X    if (istool || iscurses)
  1467. X    (void) sprintf(buf+strlen(buf), ", %d deleted", mail_stat.deleted);
  1468. X#ifdef SUNTOOL
  1469. X    if (istool) {
  1470. X    static char ic_text[4];
  1471. X    char *lbl;
  1472. X    Icon icon;
  1473. X    extern struct pixrect mail_icon_image1, mail_icon_image2;
  1474. X    (void) sprintf(ic_text, "%3d", msg_cnt);
  1475. X    if (!(lbl = (char *)window_get(tool, FRAME_LABEL)) || strcmp(lbl, buf))
  1476. X        (void) window_set(tool, FRAME_LABEL, buf, NULL);
  1477. X    icon = (Icon) window_get(tool, FRAME_ICON);
  1478. X    (void) icon_set(icon,
  1479. X        ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  1480. X                &mail_icon_image2 : &mail_icon_image1,
  1481. X        NULL);
  1482. X    if (!chk_option("quiet", "iconlabel"))
  1483. X        (void) icon_set(icon, ICON_LABEL, ic_text, NULL);
  1484. X    else
  1485. X        (void) icon_set(icon, ICON_LABEL, NO_STRING, NULL);
  1486. X    (void) window_set(tool, FRAME_ICON, icon, NULL);
  1487. X    } else
  1488. X#endif /* SUNTOOL */
  1489. X
  1490. X#ifdef CURSES
  1491. X    if (iscurses) {
  1492. X        move (0, 0);
  1493. X        printw("%-3d %-.*s",
  1494. X        ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  1495. X    } else
  1496. X#endif /* CURSES */
  1497. X        puts(buf);
  1498. X    return;
  1499. X}
  1500. X
  1501. X/*
  1502. X * Construct a prompt for the given message number using the given format
  1503. X */
  1504. Xchar *
  1505. Xformat_prompt(num, fmt)
  1506. Xint num;
  1507. Xchar *fmt;
  1508. X{
  1509. X    static char buf[MAXPATHLEN];
  1510. X    register char *p, *b = buf, *mf;
  1511. X
  1512. X    if (is_shell)
  1513. X    mf = mailfile;
  1514. X    else
  1515. X    mf = "[no folder]";
  1516. X
  1517. X    for (p = fmt; *p; p++)
  1518. X    if (*p == '\\')
  1519. X        switch (*++p) {
  1520. X        case 'n': case 'r': *b++ = '\n';
  1521. X        when 't': *b++ = '\t';
  1522. X        otherwise: *b++ = *p;
  1523. X        }
  1524. X    else if (*p == '%')
  1525. X        switch (*++p) {
  1526. X        case 'm':
  1527. X            b += strlen(sprintf(b,"%d",(msg_cnt)? num + 1 : 0));
  1528. X        when 't':
  1529. X            b += strlen(sprintf(b, "%d", msg_cnt));
  1530. X        when 'd':
  1531. X            b += strlen(sprintf(b, "%d", mail_stat.deleted));
  1532. X        when 'u':
  1533. X            b += strlen(sprintf(b, "%d", mail_stat.unread));
  1534. X        when 'n':
  1535. X            b += strlen(sprintf(b, "%d", mail_stat.new));
  1536. X        when 'f':
  1537. X        {
  1538. X            char *tail = rindex(mf, '/'); 
  1539. X            if (tail && tail[1])
  1540. X            b += Strcpy(b, tail+1);
  1541. X            else {
  1542. X            /* Fall through */
  1543. X        case 'F':
  1544. X            b += Strcpy(b, mf);
  1545. X            }
  1546. X            if (ison(glob_flags, READ_ONLY))
  1547. X            b += Strcpy(b, " [read-only]");
  1548. X        }
  1549. X        when 'T': case 'D': case 'Y': case 'y':
  1550. X        case 'M': case 'N': case 'W':
  1551. X            b += Strcpy(b, Time(p, (long)0));
  1552. X        otherwise: *b++ = *p;
  1553. X        }
  1554. X    else if (*p == '!')
  1555. X        b += strlen(sprintf(b, "%d", hist_no+1));
  1556. X    else
  1557. X        *b++ = *p;
  1558. X    *b = 0;
  1559. X    return buf;
  1560. X}
  1561. X
  1562. X/*
  1563. X *  For uucp mailers that use >From lines with "remote from <path>":
  1564. X * (where "path" is a hostname or pathnames)
  1565. X *
  1566. X *  a. Set the return_path to the empty string.
  1567. X *  b. For each From_ or >From_ line:
  1568. X *  c. Save the username (second token).
  1569. X *  d. Save the date (3-7 tokens).
  1570. X *  e. If it has a "remote from" then append the remote host
  1571. X *    (last token) followed by a "!" to the return_path.
  1572. X *  f. If the saved username has a '@' but no '!' then convert it
  1573. X *    to UUCP path form.
  1574. X *  g. Append the saved username to return_path.
  1575. X */
  1576. Xparse_from(fp, path)
  1577. XFILE *fp;
  1578. Xchar path[];
  1579. X{
  1580. X    char user[256], buf[256]; /* max size for each line in a mail file */
  1581. X    register char *p;
  1582. X    long save_offset = ftell(fp);
  1583. X
  1584. X    path[0] = '\0';
  1585. X    while (fgets(buf, sizeof buf, fp)) {
  1586. X    if (strncmp(buf, ">From ", 6))
  1587. X        break;
  1588. X    p = buf + 6;
  1589. X
  1590. X    (void) sscanf(p, "%s", user);
  1591. X
  1592. X    while (p = index(p+1, 'r')) {
  1593. X        if (!strncmp(p, "remote from ", 12)) {
  1594. X        char *p2 = path+strlen(path);
  1595. X        skipspaces(12);
  1596. X        (void) sscanf(p, "%s", p2); /* add the new machine to current path */
  1597. X        (void) strcat(p2, "!");
  1598. X        break;
  1599. X        }
  1600. X    }
  1601. X
  1602. X    if (p)
  1603. X        (void) bang_form(path + strlen(path), user);
  1604. X    save_offset = ftell(fp);
  1605. X    }
  1606. X    (void) fseek(fp, save_offset, L_SET);
  1607. X}
  1608. X
  1609. X/*
  1610. X * Scan a file and select messages from it and append them to the current folder
  1611. X *
  1612. X * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
  1613. X * and scan for messages.  Append all messages found until EOF.
  1614. X *
  1615. X * If "append" is 2, we're merging in a new file, so start at the end of
  1616. X * the present folder and append all messages found until EOF.
  1617. X *
  1618. X * If "append" is 0, then the message separator must exist once and
  1619. X * only once.  All extra occurrences of the separator is preceded by a '>'.
  1620. X * The list argument will be the message number to replace in the current
  1621. X * folder with the message read in from other filename.
  1622. X */
  1623. Xload_folder(file, append, list)
  1624. Xchar *file, *list;
  1625. Xint append;
  1626. X{
  1627. X    char    buf[BUFSIZ];
  1628. X    int        lines = 0, msg_found = 0, had_error = 1;
  1629. X    int        get_status = 1, cnt;
  1630. X    long    bytes, ftell();
  1631. X    struct msg  old;
  1632. X    char    *p, date[64];
  1633. X    FILE    *fp;
  1634. X#ifdef MMDF
  1635. X    int        begin_sep = 0; /* track beginning vs ending separators */
  1636. X#endif /* MMDF */
  1637. X
  1638. X    if (!(fp = lock_fopen(file, "r"))) {
  1639. X    error("Unable to open %s", file);
  1640. X    return -1;
  1641. X    }
  1642. X
  1643. X    if (append) {
  1644. X    cnt = msg_cnt;
  1645. X    (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
  1646. X    } else {
  1647. X    cnt = (int)list;
  1648. X    old = msg[cnt];
  1649. X    }
  1650. X
  1651. X    if (isoff(glob_flags, READ_ONLY)) {
  1652. X    if (tmpf)
  1653. X        (void) fclose(tmpf);
  1654. X    if (!(tmpf = mask_fopen(tempfile, "a"))) {
  1655. X        error("Unable to open %s for appending", tempfile);
  1656. X        close_lock(file, fp);
  1657. X        return -1;
  1658. X    }
  1659. X    (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
  1660. X    } else if (append == 2) {
  1661. X    /* you can't merge in a folder to a read-only folder */
  1662. X    close_lock(file, fp);
  1663. X    return -1;
  1664. X    }
  1665. X
  1666. X#ifdef MMDF
  1667. X    if (!append) {
  1668. X    (void) strcpy(buf, MSG_SEPARATOR);
  1669. X    goto do_headers;
  1670. X    }
  1671. X#endif /* MMDF */
  1672. X    buf[0] = 0;
  1673. X    while (fgets(buf, sizeof (buf), fp)) {
  1674. X#ifndef MSG_SEPARATOR
  1675. X    int warn = ison(glob_flags, WARNING);
  1676. X    turnoff(glob_flags, WARNING);
  1677. X    if (!strncmp(buf, "From ", 5)) {
  1678. X        p = buf + 5;    /* skip "From " */
  1679. X        skipspaces(0);
  1680. X        p = any(p, " \t");    /* skip the address */
  1681. X    } else
  1682. X        p = buf;
  1683. X    if (p > buf && (p = parse_date(p + 1)) && strcpy(date, p))
  1684. X#else /* MSG_SEPARATOR */
  1685. X    if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  1686. X#endif /* MSG_SEPARATOR */
  1687. X    {
  1688. X#ifdef MMDF
  1689. X        if (!append)
  1690. X        (void) fputc('>', tmpf);
  1691. X        else if (begin_sep = !begin_sep)
  1692. Xdo_headers:
  1693. X#else /* MMDF */
  1694. X        if (!append && msg_found)
  1695. X        (void) fputc('>', tmpf);
  1696. X        else
  1697. X#endif /* MMDF */
  1698. X        {
  1699. X        msg_found++;
  1700. X        had_error = 0;
  1701. X        if (append && cnt == MAXMSGS-append) {
  1702. X            wprint("WARNING: exceeded %d messages.\n", MAXMSGS-append);
  1703. X            wprint("Not all messages have been loaded.\n");
  1704. X            msg_cnt--;
  1705. X            had_error++;
  1706. X            break;
  1707. X        }
  1708. X        if (ison(glob_flags, READ_ONLY))
  1709. X            bytes = ftell(fp) - strlen(buf);
  1710. X        else {
  1711. X            char path[256];
  1712. X            parse_from(fp, path);
  1713. X            if (path[0])
  1714. X            (void)sprintf(buf,"From %s %s", path,
  1715. X                        date_to_ctime(date));
  1716. X            bytes = ftell(tmpf);
  1717. X        }
  1718. X        /* finish up message structure from previous message.
  1719. X         * if this is incorporating new mail, check "lines" to
  1720. X         * see if previous message has already been set!
  1721. X         */
  1722. X        if (cnt && lines) {
  1723. X            msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
  1724. X            msg[cnt-1].m_lines = lines;
  1725. X        }
  1726. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1727. X            error(tempfile);
  1728. X            had_error++;
  1729. X            break;
  1730. X        }
  1731. X        msg[cnt].m_offset = bytes;
  1732. X        msg[cnt].m_flags = 0L;
  1733. X#ifdef MSG_SEPARATOR
  1734. X        lines = 0;
  1735. X#else /* MSG_SEPARATOR */
  1736. X        lines = 1; /* count the From_ line */
  1737. X        if (warn)
  1738. X            turnon(glob_flags, WARNING);
  1739. X        strdup(msg[cnt].m_date_recv, date);
  1740. X#endif /* MSG_SEPARATOR */
  1741. X        turnon(msg[cnt].m_flags, UNREAD); /* initialize */
  1742. X        /* we've read the "From " line(s), now read the rest of
  1743. X         * the message headers till we get to a blank line.
  1744. X         */
  1745. X        while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
  1746. X            p = buf;
  1747. X            if (!strncmp(buf, "Date:", 5))
  1748. X            strdup(msg[cnt].m_date_sent, parse_date(p+5));
  1749. X            if (get_status &&
  1750. X                !(get_status = strncmp(p, "Status:", 7))) {
  1751. X            /* new mail should not have a Status: field! */
  1752. X            turnon(msg[cnt].m_flags, OLD);
  1753. X            for (p += 7 ; *p != '\n'; p++) {
  1754. X                if (isspace(*p))
  1755. X                continue;
  1756. X                switch(*p) {
  1757. X                case 'R': turnoff(msg[cnt].m_flags, UNREAD);
  1758. X                when 'P': turnon(msg[cnt].m_flags, UNREAD);
  1759. X                when 'N': turnon(msg[cnt].m_flags, UNREAD);
  1760. X                      turnoff(msg[cnt].m_flags, OLD);
  1761. X                when 'S': turnon(msg[cnt].m_flags, SAVED);
  1762. X                when 'r': turnon(msg[cnt].m_flags, REPLIED);
  1763. X                when 'O': ; /* do nothing */
  1764. X                when 'f': turnon(msg[cnt].m_flags, FORWARD);
  1765. X                when 'p': turnon(msg[cnt].m_flags, PRINTED);
  1766. X                otherwise :
  1767. X                    if (ison(glob_flags, WARNING))
  1768. X                    print("unknown msg status flag: %c\n",
  1769. X                        *p);
  1770. X                }
  1771. X            }
  1772. X            }
  1773. X            if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
  1774. X            error(tempfile);
  1775. X            had_error++;
  1776. X            break;
  1777. X            }
  1778. X            lines++;
  1779. X        }
  1780. X        if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
  1781. X            if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
  1782. X            wprint("Message %d has *no* date!?\n", cnt+1);
  1783. X            msg[cnt].m_date_sent = msg[cnt].m_date_recv =
  1784. X                "0000000000XXX";
  1785. X            } else
  1786. X            strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
  1787. X        else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
  1788. X            strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
  1789. X        if (had_error)
  1790. X            break;
  1791. X        if (append && list)
  1792. X            set_msg_bit(list, cnt);
  1793. X        if (append)
  1794. X            cnt = ++msg_cnt;
  1795. X        get_status = 1;
  1796. X        }
  1797. X    } else if (!msg_found && buf[0] != '\n') {
  1798. X        /* Allow leading blank lines, but anything else is wrong */
  1799. X        lines++;
  1800. X        had_error++;
  1801. X        break;
  1802. X    }
  1803. X    if (msg_found) {
  1804. X        lines++;
  1805. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1806. X        error(tempfile);
  1807. X        had_error++;
  1808. X        break;
  1809. X        }
  1810. X    }
  1811. X    }
  1812. X    if (msg_found && append != 1)
  1813. X    turnon(glob_flags, DO_UPDATE);
  1814. X#ifdef MMDF
  1815. X    if (!append)
  1816. X    (void) fputs(END_MSG_SEP, tmpf);
  1817. X#endif /* MMDF */
  1818. X    if (had_error) {
  1819. X    if (!append)
  1820. X        msg[cnt] = old;
  1821. X    else if (msg_found && append == 1 && cnt == MAXMSGS-append) {
  1822. X        /* reset fp to the beginning of the not-loaded message */
  1823. X        bytes = ftell(fp) - strlen(buf);
  1824. X        (void) fseek(fp, bytes, L_SET);
  1825. X    }
  1826. X    if (!msg_found) {
  1827. X        if (!append)
  1828. X        print("File not left in correct message format.\n");
  1829. X        else if (cnt == 0) {
  1830. X        if (buf[0]) 
  1831. X            print("\"%s\" does not seem to be a folder\n", file);
  1832. X        else
  1833. X            had_error = 0;    /* empty files are OK */
  1834. X        }
  1835. X    }
  1836. X    } else {
  1837. X    if (append)
  1838. X        cnt--;
  1839. X    if (isoff(glob_flags, READ_ONLY))
  1840. X        msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
  1841. X    else
  1842. X        msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
  1843. X    msg[cnt].m_lines = lines;
  1844. X    /* remember where we were to seek to for when we append new mail */ 
  1845. X    if (append)
  1846. X        cnt++;
  1847. X    }
  1848. X    if (append == 1) /* merge_folders takes care of this for append == 2 */
  1849. X    msg[cnt].m_offset = ftell(fp);
  1850. X    close_lock(file, fp);
  1851. X    if (isoff(glob_flags, READ_ONLY)) {
  1852. X    if (had_error && msg_found && append == 1 && cnt == MAXMSGS-append) {
  1853. X        wprint("Using read-only mode.\n");
  1854. X        turnon(glob_flags, READ_ONLY);
  1855. X        had_error = 0;    /* return successfully anyway */
  1856. X    }
  1857. X    (void) fclose(tmpf);
  1858. X    if (!(tmpf = fopen(tempfile, "r"))) {
  1859. X        error("Unable to open %s for reading", tempfile);
  1860. X        return -1;
  1861. X    }
  1862. X    }
  1863. X    return !had_error;
  1864. X}
  1865. END_OF_FILE
  1866. if test 27478 -ne `wc -c <'mush/msgs.c'`; then
  1867.     echo shar: \"'mush/msgs.c'\" unpacked with wrong size!
  1868. fi
  1869. # end of 'mush/msgs.c'
  1870. fi
  1871. echo shar: End of archive 11 \(of 19\).
  1872. cp /dev/null ark11isdone
  1873. MISSING=""
  1874. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1875.     if test ! -f ark${I}isdone ; then
  1876.     MISSING="${MISSING} ${I}"
  1877.     fi
  1878. done
  1879. if test "${MISSING}" = "" ; then
  1880.     echo You have unpacked all 19 archives.
  1881.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1882. else
  1883.     echo You still need to unpack the following archives:
  1884.     echo "        " ${MISSING}
  1885. fi
  1886. ##  End of shell archive.
  1887. exit 0
  1888.  
  1889.