home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.11 < prev    next >
Encoding:
Text File  |  1990-05-06  |  54.3 KB  |  1,882 lines

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