home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3962 < prev    next >
Encoding:
Internet Message Format  |  1991-09-04  |  49.7 KB

  1. Path: wupost!uunet!mcsun!unido!estevax!norisc!iain
  2. From: iain@norisc.UUCP (Iain Lea)
  3. Newsgroups: alt.sources
  4. Subject: tin v1.0 Patchlevel 1 Newsreader (part 05/08)
  5. Message-ID: <603@norisc.UUCP>
  6. Date: 3 Sep 91 11:00:11 GMT
  7. Sender: iain@norisc.UUCP (Iain Lea)
  8. Organization: What organization?
  9. Lines: 2305
  10.  
  11. Submitted-by: iain@estevax.uucp
  12. Archive-name: tin1.0/part05
  13.  
  14. #!/bin/sh
  15. # this is tin.shar.05 (part 5 of tin1.0)
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file nntp.h continued
  18. #
  19. if touch 2>&1 | fgrep '[-amc]' > /dev/null
  20.  then TOUCH=touch
  21.  else TOUCH=true
  22. fi
  23. if test ! -r shar3_seq_.tmp; then
  24.     echo "Please unpack part 1 first!"
  25.     exit 1
  26. fi
  27. (read Scheck
  28.  if test "$Scheck" != 5; then
  29.     echo "Please unpack part $Scheck next!"
  30.     exit 1
  31.  else
  32.     exit 0
  33.  fi
  34. ) < shar3_seq_.tmp || exit 1
  35. echo "x - Continuing file nntp.h"
  36. sed 's/^X//' << 'SHAR_EOF' >> nntp.h &&
  37. X#define    ERR_NOARTIG    423    /* No such article in this group */
  38. X#define ERR_NOART    430    /* No such article at all */
  39. X#define ERR_GOTIT    435    /* Already got that article, don't send */
  40. X#define ERR_XFERFAIL    436    /* Transfer failed */
  41. X#define    ERR_XFERRJCT    437    /* Article rejected, don't resend */
  42. X#define    ERR_NOPOST    440    /* Posting not allowed */
  43. X#define    ERR_POSTFAIL    441    /* Posting failed */
  44. X
  45. X#define    ERR_COMMAND    500    /* Command not recognized */
  46. X#define    ERR_CMDSYN    501    /* Command syntax error */
  47. X#define    ERR_ACCESS    502    /* Access to server denied */
  48. X#define ERR_FAULT    503    /* Program fault, command not performed */
  49. X
  50. X/* RFC 977 defines this; don't change it. */
  51. X
  52. X#define    NNTP_STRLEN    512
  53. SHAR_EOF
  54. echo "File nntp.h is complete" &&
  55. $TOUCH -am 0903095091 nntp.h &&
  56. chmod 0600 nntp.h ||
  57. echo "restore of nntp.h failed"
  58. set `wc -c nntp.h`;Wc_c=$1
  59. if test "$Wc_c" != "3688"; then
  60.     echo original size 3688, current size $Wc_c
  61. fi
  62. # ============= open.c ==============
  63. echo "x - extracting open.c (Text)"
  64. sed 's/^X//' << 'SHAR_EOF' > open.c &&
  65. X/*
  66. X *  Project   : tin - a visual threaded usenet newsreader
  67. X *  Module    : open.c
  68. X *  Author    : R.Skrenta / I.Lea
  69. X *  Created   : 01-04-91
  70. X *  Updated   : 28-08-91
  71. X *  Release   : 1.0
  72. X *  Notes     : reads news locally (/usr/spool/news) or via NNTP
  73. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  74. X *                You may  freely  copy or  redistribute  this software,
  75. X *              so  long as there is no profit made from its use, sale
  76. X *              trade or  reproduction.  You may not change this copy-
  77. X *              right notice, and it must be included in any copy made
  78. X */
  79. X
  80. X#include    "tin.h"
  81. X#ifdef USE_NNTP
  82. X#include    "nntp.h"
  83. X#endif
  84. X
  85. X/* Hopefully one of these is right for you. */
  86. X
  87. X#ifdef BSD
  88. X#    include <sys/dir.h>
  89. X#    define        DIR_BUF        struct direct
  90. X#    define        D_LENGTH    d_namlen
  91. X#endif
  92. X#ifdef M_XENIX
  93. X#    include <sys/ndir.h>
  94. X#    define        DIR_BUF        struct direct
  95. X#    define        D_LENGTH    d_namlen
  96. X#endif
  97. X#ifndef DIR_BUF
  98. X#ifdef sorix960
  99. X#    include    <sys/dirent.h>
  100. X#else
  101. X#    include    <dirent.h>
  102. X#endif
  103. X#    define        DIR_BUF        struct dirent
  104. X#    define        D_LENGTH    d_reclen
  105. X#endif
  106. X
  107. X#ifdef USE_NNTP
  108. Xint compiled_with_nntp = TRUE;        /* used in mail_bug_report() info */
  109. X#else
  110. Xint compiled_with_nntp = FALSE;
  111. X#endif
  112. X
  113. Xchar server_name[LEN+1];
  114. X
  115. X
  116. Xchar *is_remote ()
  117. X{
  118. X    server_name[0] = '\0';
  119. X    
  120. X#ifdef USE_NNTP
  121. X    if (read_news_via_nntp) {
  122. X        if (nntp_server[0]) {
  123. X            sprintf (server_name, " (%s)", nntp_server);
  124. X        } else {
  125. X            if (getserverbyfile (NNTP_SERVER_FILE)) {
  126. X                sprintf (server_name, " (%s)", getserverbyfile (NNTP_SERVER_FILE));
  127. X            } else {
  128. X                strcpy (server_name, " (NO SERVER)");
  129. X            }
  130. X        }
  131. X    }
  132. X#endif
  133. X
  134. X    return (server_name);
  135. X}
  136. X
  137. X
  138. Xvoid nntp_startup()
  139. X{
  140. X#ifdef USE_NNTP    
  141. X    char *server_name;
  142. X    int ret;
  143. X    extern char *getenv();
  144. X
  145. X    if (read_news_via_nntp) {
  146. X        if (nntp_server[0]) {
  147. X            strcpy (server_name, nntp_server);
  148. X        } else {
  149. X            server_name = getserverbyfile (NNTP_SERVER_FILE);
  150. X        }
  151. X        if (server_name == NULL) {
  152. X            fprintf(stderr, txt_cannot_get_nntp_server_name);
  153. X            fprintf(stderr, txt_server_name_in_file_env_var, NNTP_SERVER_FILE);
  154. X            exit(1);
  155. X        }
  156. X
  157. X        ret = server_init (server_name);
  158. X/*
  159. X        handle_server_response (ret, server_name);
  160. X*/        
  161. X        switch (ret) {
  162. X        case OK_CANPOST:
  163. X        case OK_NOPOST:
  164. X            break;    
  165. X
  166. X        case -1:
  167. X            fprintf (stderr, txt_failed_to_connect_to_server, server_name);
  168. X            exit (1);
  169. X
  170. X        default:
  171. X            fprintf (stderr, txt_rejected_by_nntpserver, ret);
  172. X            exit (1);
  173. X        }
  174. X    }
  175. X#endif    
  176. X}
  177. X
  178. Xvoid nntp_finish()
  179. X{
  180. X#ifdef USE_NNTP
  181. X    if (read_news_via_nntp) {
  182. X        close_server();
  183. X    }
  184. X#endif    
  185. X}
  186. X
  187. X
  188. XFILE *open_active_fp()
  189. X{
  190. X    FILE *fp;
  191. X
  192. X    if (read_news_via_nntp) {
  193. X#ifdef USE_NNTP
  194. X        put_server("list");
  195. X        if (get_respcode() != OK_GROUPS) {
  196. X            return NULL;
  197. X        }
  198. X        return nntp_to_fp();
  199. X#endif        
  200. X    } else {
  201. X        if ((fp = fopen(active_file, "r")) == NULL) {
  202. X            fprintf(stderr, txt_cannot_open, active_file);
  203. X            perror("");
  204. X            exit(1);
  205. X        }
  206. X        return fp;
  207. X    }
  208. X}
  209. X
  210. X
  211. XFILE *open_art_fp(group_path, art)
  212. X    char *group_path;
  213. X    long art;
  214. X{
  215. X    char buf[LEN+1];
  216. X    struct stat sb;
  217. X    extern long note_size;
  218. X
  219. X    if (read_news_via_nntp) {
  220. X#ifdef USE_NNTP
  221. X        sprintf(buf, "article %ld", art);
  222. X
  223. X        put_server(buf);
  224. X        if (get_respcode() != OK_ARTICLE) {
  225. X            return NULL;
  226. X        }
  227. X
  228. X        return nntp_to_fp();
  229. X#endif
  230. X    } else {
  231. X        sprintf(buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  232. X
  233. X        if (stat(buf, &sb) < 0) {
  234. X            note_size = 0;
  235. X        } else {
  236. X            note_size = sb.st_size;
  237. X        }
  238. X
  239. X        return fopen(buf, "r");
  240. X    }
  241. X}
  242. X
  243. X
  244. Xint open_header_fd (group_path, art)
  245. X    char *group_path;
  246. X    long art;
  247. X{
  248. X    char buf[LEN+1];
  249. X
  250. X    if (read_news_via_nntp) {
  251. X#ifdef USE_NNTP    
  252. X        sprintf(buf, "head %ld", art);
  253. X        
  254. X        put_server (buf);
  255. X        if (get_respcode () != OK_HEAD) {
  256. X            return -1;
  257. X        }
  258. X
  259. X        return nntp_to_fd ();
  260. X#endif        
  261. X    } else {
  262. X        sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  263. X        return open (buf, 0);
  264. X    }
  265. X}
  266. X
  267. X/*
  268. X *  Longword comparison routine for the qsort()
  269. X */
  270. X
  271. Xint base_comp (a, b)
  272. X    long *a;
  273. X    long *b;
  274. X{
  275. X
  276. X    if (*a < *b)
  277. X        return -1;
  278. X    if (*a > *b)
  279. X        return 1;
  280. X    return 0;
  281. X}
  282. X
  283. X
  284. X/*
  285. X *  Read the article numbers existing in a group's spool directory
  286. X *  into base[] and sort them.  base_top is one past top.
  287. X */
  288. X
  289. Xvoid setup_base (group, group_path)
  290. X    char *group;
  291. X    char *group_path;
  292. X{
  293. X    char buf[LEN+1];
  294. X#ifdef USE_NNTP
  295. X    char line[NNTP_STRLEN];
  296. X#endif
  297. X    DIR *d;
  298. X    DIR_BUF *e;
  299. X    long art, start, last, dummy, count;
  300. X
  301. X    top_base = 0;
  302. X
  303. X    if (read_news_via_nntp) {
  304. X#ifdef USE_NNTP
  305. X        sprintf (buf, "group %s", group);
  306. X        put_server (buf);
  307. X
  308. X        if (get_server(line, NNTP_STRLEN) == -1) {
  309. X            fprintf(stderr, txt_connection_to_server_broken);
  310. X            tin_done(1);
  311. X        }
  312. X
  313. X        if (atoi(line) != OK_GROUP) {
  314. X            return;
  315. X        }
  316. X
  317. X        sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last);
  318. X        if (last - count > start) {
  319. X            start = last - count;
  320. X        }
  321. X
  322. X        while (start <= last) {
  323. X            if (top_base >= max_art) {
  324. X                expand_art();
  325. X            }
  326. X            base[top_base++] = start++;
  327. X        }
  328. X#endif
  329. X    } else {
  330. X        sprintf(buf, "%s/%s", SPOOLDIR, group_path);
  331. X
  332. X        if (access(buf, 4) != 0) {
  333. X            return;
  334. X        }
  335. X
  336. X        d = opendir(buf);
  337. X        if (d != NULL) {
  338. X            while ((e = readdir(d)) != NULL) {
  339. X                art = my_atol (e->d_name, (int) e->D_LENGTH);
  340. X                if (art >= 0) {
  341. X                    if (top_base >= max_art)
  342. X                        expand_art();
  343. X                    base[top_base++] = art;
  344. X                }
  345. X            }
  346. X            closedir(d);
  347. X            qsort(base, top_base, sizeof(long), base_comp);
  348. X        }
  349. X    }
  350. X}
  351. X
  352. X/*
  353. X *  get_respcode
  354. X *  get a response code from the server and return it to the caller
  355. X */
  356. X
  357. Xint get_respcode()
  358. X{
  359. X#ifdef USE_NNTP
  360. X    char line[NNTP_STRLEN];
  361. X
  362. X    if (get_server(line, NNTP_STRLEN) == -1) {
  363. X        fprintf(stderr, txt_connection_to_server_broken);
  364. X        tin_done(1);
  365. X    }
  366. X
  367. X    return atoi(line);
  368. X#endif
  369. X}
  370. X
  371. X
  372. Xint stuff_nntp (fnam)
  373. X    char *fnam;
  374. X{
  375. X#ifdef USE_NNTP
  376. X    FILE *fp;
  377. X    char line[NNTP_STRLEN];
  378. X    extern char *mktemp();
  379. X    struct stat sb;
  380. X    extern long note_size;
  381. X
  382. X    strcpy(fnam, "/tmp/tin_nntpXXXXXX");
  383. X    mktemp(fnam);
  384. X
  385. X    if ((fp = fopen(fnam, "w")) == NULL) {
  386. X        error_message (txt_stuff_nntp_cannot_open, fnam);
  387. X        return FALSE;
  388. X    }
  389. X
  390. X    while (1) {
  391. X        if (get_server(line, NNTP_STRLEN) == -1) {
  392. X            fprintf(stderr, txt_connection_to_server_broken);
  393. X            tin_done (1);
  394. X        }
  395. X        if (strcmp(line, ".") == 0)
  396. X            break;            /* end of text */
  397. X        strcat(line, "\n");
  398. X        if (line[0] == '.')        /* reduce leading .'s */
  399. X            fputs(&line[1], fp);
  400. X        else
  401. X            fputs(line, fp);
  402. X    }
  403. X    fclose(fp);
  404. X
  405. X    if (stat(fnam, &sb) < 0)
  406. X        note_size = 0;
  407. X    else
  408. X        note_size = sb.st_size;
  409. X
  410. X    return TRUE;
  411. X#endif
  412. X}
  413. X
  414. X
  415. XFILE *nntp_to_fp()
  416. X{
  417. X    char fnam[LEN+1];
  418. X    FILE *fp;
  419. X
  420. X    if (!stuff_nntp(fnam))
  421. X        return NULL;
  422. X
  423. X    fp = fopen(fnam, "r");
  424. X    if (fp == NULL) {
  425. X        fprintf(stderr, txt_nntp_to_fp_cannot_reopen, fnam);
  426. X        perror("");
  427. X        return NULL;
  428. X    }
  429. X    unlink(fnam);
  430. X    return fp;
  431. X}
  432. X
  433. X
  434. Xint nntp_to_fd ()
  435. X{
  436. X#ifdef USE_NNTP
  437. X    char fnam[LEN+1];
  438. X    int fd;
  439. X
  440. X    if (! stuff_nntp (fnam))
  441. X        return -1;
  442. X
  443. X    if ((fd = open (fnam, 0)) == -1) {
  444. X        fprintf (stderr, txt_nntp_to_fd_cannot_reopen, fnam);
  445. X        perror ("");
  446. X        return -1;
  447. X    }
  448. X    unlink (fnam);
  449. X    return fd;
  450. X#endif
  451. X}
  452. X
  453. SHAR_EOF
  454. $TOUCH -am 0903095091 open.c &&
  455. chmod 0600 open.c ||
  456. echo "restore of open.c failed"
  457. set `wc -c open.c`;Wc_c=$1
  458. if test "$Wc_c" != "6732"; then
  459.     echo original size 6732, current size $Wc_c
  460. fi
  461. # ============= page.c ==============
  462. echo "x - extracting page.c (Text)"
  463. sed 's/^X//' << 'SHAR_EOF' > page.c &&
  464. X/*
  465. X *  Project   : tin - a visual threaded usenet newsreader
  466. X *  Module    : page.c
  467. X *  Author    : R.Skrenta / I.Lea
  468. X *  Created   : 01-04-91
  469. X *  Updated   : 03-09-91
  470. X *  Release   : 1.0
  471. X *  Notes     :
  472. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  473. X *                You may  freely  copy or  redistribute  this software,
  474. X *              so  long as there is no profit made from its use, sale
  475. X *              trade or  reproduction.  You may not change this copy-
  476. X *              right notice, and it must be included in any copy made
  477. X */
  478. X
  479. X#include    "tin.h"
  480. X
  481. X#define        NOTE_UNAVAIL    -1
  482. X
  483. Xextern int cur_groupnum;
  484. X
  485. Xchar note_h_path[LEN+1];            /* Path:    */
  486. Xchar note_h_date[LEN+1];            /* Date:    */
  487. Xchar note_h_subj[LEN+1];            /* Subject:    */
  488. Xchar note_h_from[LEN+1];            /* From:    */
  489. Xchar note_h_org[LEN+1];                /* Organization: */
  490. Xchar note_h_newsgroups[LEN+1];        /* Newsgroups:    */
  491. Xchar note_h_messageid[LEN+1];        /* Message-ID:    */
  492. Xchar note_h_distrib[LEN+1];            /* Distribution: */
  493. Xchar note_h_followup[LEN+1];        /* Followup-To: */
  494. X
  495. Xchar note_full_name[100];
  496. Xchar note_from_addr[100];
  497. Xchar *glob_page_group;
  498. X
  499. XFILE *note_fp;                /* the body of the current article */
  500. X
  501. Xint    note_line;
  502. Xint    note_page;                    /* what page we're on */
  503. Xint    note_end;                    /* we're done showing this article */
  504. Xint    rotate;                        /* 0=normal, 13=rot13 decode */
  505. Xint last_resp;        /* current & previous article for - command */
  506. Xint this_resp;
  507. Xint glob_respnum;
  508. X
  509. Xlong    note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  510. Xlong note_size;                    /* stat size in bytes of article */
  511. X
  512. X
  513. Xint show_page (respnum, group, group_path)
  514. X    int respnum;
  515. X    char *group;
  516. X    char *group_path;
  517. X{
  518. X    char ch;
  519. X    int i, n;
  520. X    int kill_state = NO_KILLING;
  521. X    int old_artnum;
  522. X    int old_sort_art_type = sort_art_type;
  523. X    int old_top;
  524. X    long art;
  525. X
  526. Xrestart:
  527. X
  528. X    glob_respnum = respnum;
  529. X    glob_page_group = group;
  530. X
  531. X#ifdef SIGTSTP
  532. X    if (do_sigtstp) {
  533. X#ifdef POSIX_JOB_CONTROL
  534. X        sigemptyset (&page_act.sa_mask);
  535. X        page_act.sa_flags = SA_RESTART | SA_RESETHAND;
  536. X        page_act.sa_handler = page_suspend;
  537. X        sigaction (SIGTSTP, &page_act, 0L);
  538. X#else
  539. X        signal (SIGTSTP, page_suspend);
  540. X#endif
  541. X    }
  542. X#endif
  543. X
  544. X#ifdef SIGWINCH
  545. X    signal (SIGWINCH, page_resize);
  546. X#endif
  547. X
  548. X    if (respnum != this_resp) {       /* remember current & previous */
  549. X        last_resp = this_resp;       /* articles for - command */
  550. X        this_resp = respnum;
  551. X    }
  552. X
  553. X    rotate = 0;            /* normal mode, not rot13 */
  554. X    art = arts[respnum].artnum;
  555. X    arts[respnum].unread = ART_READ;    /* mark article as read */
  556. X    open_note (art, group_path);
  557. X
  558. X    if (note_page == NOTE_UNAVAIL) {
  559. X        ClearScreen();
  560. X        printf(txt_art_unavailable, art);
  561. X        fflush(stdout);
  562. X    } else {
  563. X        show_note_page (respnum, group);
  564. X    }
  565. X
  566. X    while (1) {
  567. X        ch = ReadCh();
  568. X
  569. X        if (ch >= '0' && ch <= '9') {
  570. X
  571. X            n = prompt_response(ch, respnum);
  572. X            if (n != -1) {
  573. X                respnum = n;
  574. X                goto restart;
  575. X            }
  576. X
  577. X        } else switch (ch) {
  578. X            case 27:
  579. X                ch = ReadCh ();
  580. X                if (ch == '[' || ch == 'O')
  581. X                    ch = ReadCh ();
  582. X                switch (ch) {
  583. X                case 'G':        /* ansi  PgDn */
  584. X                case 'U':        /* at386 PgDn */
  585. X                    goto page_down;
  586. X
  587. X                case 'I':        /* ansi  PgUp */
  588. X                case 'V':        /* at386 PgUp */
  589. X                    goto page_up;
  590. X
  591. X                case 'H':        /* at386 Home */
  592. X                    goto begin_of_article;
  593. X
  594. X                case 'F':        /* ansi End */
  595. X                case 'Y':        /* at386 End */
  596. X                    goto end_of_article;
  597. X                }
  598. X                break;
  599. X
  600. X            case '!':
  601. X                shell_escape ();
  602. X                redraw_page (respnum, group);
  603. X                break;
  604. X
  605. X            case '$':    /* goto end of article */
  606. Xend_of_article:            
  607. X                if (show_last_page ()) {
  608. X                    show_note_page(respnum, group);
  609. X                }
  610. X                break;
  611. X
  612. X            case '-':    /* show last viewed article */
  613. X                if (last_resp < 0) {
  614. X                    info_message(txt_no_last_message);
  615. X                    break;
  616. X                }
  617. X                note_cleanup();
  618. X                respnum = last_resp;
  619. X                goto restart;
  620. X
  621. X            case '|':    /* pipe article/thread/tagged arts to command */
  622. X                feed_articles (FEED_PIPE, PAGE_LEVEL, "Pipe", respnum, group_path);
  623. X                break;
  624. X
  625. X            case '/':    /* search forwards in article */
  626. X                if (search_article (TRUE)) {
  627. X                    show_note_page (respnum, group);
  628. X                }
  629. X                break;
  630. X
  631. X            case ctrl('D'):
  632. X            case ' ':     /* next page or response */
  633. Xpage_down:
  634. X                if (note_page == NOTE_UNAVAIL) {
  635. X                    n = next_response (respnum);
  636. X                    if (n == -1) {
  637. X                        return (which_base (respnum));
  638. X                    }
  639. X                    respnum = n;
  640. X                    goto restart;
  641. X                } else if (note_end) {
  642. X                    note_cleanup ();
  643. X                    n = next_response (respnum);
  644. X                    if (n == -1) {
  645. X                        return (which_base (respnum));
  646. X                    }
  647. X                    respnum = n;
  648. X                    goto restart;
  649. X                } else
  650. X                    show_note_page (respnum, group);
  651. X                break;
  652. X
  653. X            case '\r':
  654. X            case '\n':    /* go to start of next thread */
  655. X                note_cleanup ();
  656. X                n = next_basenote (respnum);
  657. X                if (n == -1)
  658. X                    return (which_base (respnum));
  659. X
  660. X                respnum = n;
  661. X                goto restart;
  662. X
  663. X            case '\t':     /* next page or unread response */
  664. X                if (note_page == NOTE_UNAVAIL) {
  665. X                    n = next_unread (next_response (respnum));
  666. X                    if (n == -1)
  667. X                        return (which_base (respnum));
  668. X
  669. X                    respnum = n;
  670. X                    goto restart;
  671. X
  672. X                } else if (note_end) {
  673. X                    note_cleanup();
  674. X                    n = next_unread(next_response(respnum));
  675. X                    if (n == -1)
  676. X                        return (which_base (respnum));
  677. X
  678. X                    respnum = n;
  679. X                    goto restart;
  680. X                } else
  681. X                    show_note_page(respnum, group);
  682. X                break;
  683. X
  684. X            case ctrl('H'):    /* show article headers */
  685. X                if (note_page == NOTE_UNAVAIL) {
  686. X                    n = next_response (respnum);
  687. X                    if (n == -1)
  688. X                        return (which_base (respnum));
  689. X
  690. X                    respnum = n;
  691. X                    goto restart;
  692. X                } else {
  693. X                    note_page = 0;
  694. X                    note_end = FALSE;
  695. X                    fseek(note_fp, 0L, 0);
  696. X                    show_note_page(respnum, group);
  697. X                }
  698. X                break;
  699. X
  700. X            case ctrl('K'):        /* kill article */
  701. X                if (kill_articles) {
  702. X                    if (kill_art_menu (group, respnum)) {
  703. X                        if (kill_any_articles (group)) {
  704. X                            reload_index_file (group, TRUE);
  705. X                        }
  706. X                    }
  707. X                    redraw_page(respnum, group);
  708. X                } else {
  709. X                    info_message (txt_switch_on_kill_art_menu);
  710. X                }
  711. X                break;
  712. X
  713. X            case ctrl('L'):      /* redraw current page of article */
  714. X                redraw_page (respnum, group);
  715. X                break;
  716. X
  717. X            case ctrl('R'):      /* redraw beginning of article */
  718. Xbegin_of_article:            
  719. X                if (note_page == NOTE_UNAVAIL) {
  720. X                    ClearScreen();
  721. X                    printf(txt_art_unavailable,arts[respnum].artnum);
  722. X                    fflush(stdout);
  723. X                } else {
  724. X                    note_page = 0;
  725. X                    note_end = FALSE;
  726. X                    fseek(note_fp, note_mark[0], 0);
  727. X                    show_note_page(respnum, group);
  728. X                }
  729. X                break;
  730. X
  731. X            case ctrl('X'):
  732. X            case '%':
  733. X            case 'd':    /* toggle rot-13 mode */
  734. X                if (rotate)
  735. X                    rotate = 0;
  736. X                else
  737. X                    rotate = 13;
  738. X                redraw_page (respnum, group);
  739. X                info_message (txt_toggled_rot13);
  740. X                break;
  741. X
  742. X            case 'a':    /* author search forward */
  743. X            case 'A':    /* author search backward */
  744. X                i = (ch == 'a');
  745. X                n = search_author (respnum, i);
  746. X                if (n < 0)
  747. X                    break;
  748. X                respnum = n;
  749. X                goto restart;
  750. X                break;
  751. X
  752. X            case ctrl('U'):
  753. X            case 'b':        /* back a page */
  754. Xpage_up:
  755. X                if (note_page == NOTE_UNAVAIL) {
  756. X                    note_cleanup();
  757. X                    n = prev_response(respnum);
  758. X                    if (n == -1)
  759. X                        return( which_resp(respnum) );
  760. X
  761. X                    respnum = n;
  762. X                    goto restart;
  763. X
  764. X                } else {
  765. X                    if (note_page <= 1) {
  766. X                        info_message (txt_begin_of_art);
  767. X                    } else {
  768. X                        note_page -= 2;
  769. X                        note_end = FALSE;
  770. X                        fseek(note_fp, note_mark[note_page], 0);
  771. X                        show_note_page(respnum, group);
  772. X                    }
  773. X                }
  774. X                break;
  775. X
  776. X            case 'B':    /* bug/gripe/comment mailed to author */
  777. X                mail_bug_report ();
  778. X                redraw_page (respnum, group);
  779. X                break;
  780. X                
  781. X            case 'c':    /* catchup--mark all articles as read */
  782. X                if (prompt_yn (LINES, txt_mark_all_read, 'y')) {
  783. X                    for (n = 0; n < top; n++) {
  784. X                        arts[n].unread = ART_READ;
  785. X                    }
  786. X                    fix_new_highest(cur_groupnum);
  787. X                    if (cur_groupnum + 1 < local_top) {
  788. X                        cur_groupnum++;
  789. X                    }
  790. X                    note_cleanup();
  791. X                    return -1;
  792. X                }
  793. X                break;
  794. X                
  795. X            case 'f':    /* post a followup to this article */
  796. X                if (post_response (group, FALSE)) {
  797. X                    update_newsrc (group, my_group[cur_groupnum]);
  798. X                    n = which_base (respnum);
  799. X                    note_cleanup ();
  800. X                    index_group (group, group_path);
  801. X                    read_newsrc_line (group);
  802. X                    respnum = choose_resp (n, nresp(n));
  803. X                    goto restart;
  804. X                } else
  805. X                    redraw_page (respnum, group);
  806. X                break;
  807. X
  808. X            case 'F':    /* post a followup to this article */
  809. X                if (post_response (group, TRUE)) {
  810. X                    update_newsrc (group, my_group[cur_groupnum]);
  811. X                    n = which_base (respnum);
  812. X                    note_cleanup ();
  813. X                    index_group (group, group_path);
  814. X                    read_newsrc_line (group);
  815. X                    respnum = choose_resp (n, nresp(n));
  816. X                    goto restart;
  817. X                } else
  818. X                    redraw_page (respnum, group);
  819. X                break;
  820. X
  821. X            case 'h':    /* help overview */
  822. X                show_help_page (help_page, txt_art_pager_com);
  823. X                redraw_page (respnum, group);
  824. X                break;
  825. X
  826. X            case 'H':    /* help in-depth */
  827. X                help_page_info ();
  828. X                redraw_page(respnum, group);
  829. X                break;
  830. X
  831. X            case 'i':    /* return to index page */
  832. Xreturn_to_index:
  833. X                note_cleanup ();
  834. X                if (kill_state == NO_KILLING &&
  835. X                    sort_art_type != old_sort_art_type) {
  836. X                    make_threads (TRUE);
  837. X                    find_base ();
  838. X                }
  839. X                if (kill_state == KILLING) {
  840. X                    old_top = top;
  841. X                    old_artnum = arts[respnum].artnum;
  842. X                    if (kill_articles) {
  843. X                        kill_any_articles (group);
  844. X                        reload_index_file (group, TRUE);    /* kill arts */
  845. X                    } else {
  846. X                        reload_index_file (group, FALSE);    /* unkill arts */
  847. X                    }
  848. X                    return find_new_pos (old_top, old_artnum, respnum);
  849. X                }
  850. X                return (which_base (respnum));
  851. X
  852. X            case 'I':    /* toggle inverse video */
  853. X                inverse_okay = !inverse_okay;
  854. X                if (inverse_okay)
  855. X                    info_message(txt_inverse_on);
  856. X                else
  857. X                    info_message(txt_inverse_off);
  858. X                redraw_page (respnum, group);
  859. X                break;
  860. X
  861. X            case 'k':
  862. X                if (note_page == NOTE_UNAVAIL) {
  863. X                    n = next_unread(next_response(respnum));
  864. X                    if (n == -1)
  865. X                        return (which_base (respnum));
  866. X
  867. X                    respnum = n;
  868. X                    goto restart;
  869. X
  870. X                } else {
  871. X                    note_cleanup();
  872. X                    n = next_unread(next_response(respnum));
  873. X                    if (n == -1)
  874. X                        return (which_base (respnum));
  875. X
  876. X                    respnum = n;
  877. X                    goto restart;
  878. X                }
  879. X                break;
  880. X
  881. X            case 'K':    /* mark rest of thread as read */
  882. X                for (n = respnum; n >= 0; n = arts[n].thread)
  883. X                    arts[n].unread = ART_READ;
  884. X                n = next_unread(next_response(respnum));
  885. X                if (n == -1)
  886. X                    goto return_to_index;
  887. X                else {
  888. X                    note_cleanup();
  889. X                    respnum = n;
  890. X                    goto restart;
  891. X                }
  892. X                break;
  893. X
  894. X            case 'm':    /* mail article/thread/tagged articles to somebody */
  895. X                feed_articles (FEED_MAIL, PAGE_LEVEL, "Mail", respnum, group_path);
  896. X                break;
  897. X
  898. X            case 'M':    /* options menu */
  899. X                if (change_rcfile (group, FALSE) == KILLING) {
  900. X                    kill_state = KILLING;
  901. X                } 
  902. X                redraw_page (respnum, group);
  903. X                break;
  904. X
  905. X            case 'n':    /* skip to next article */
  906. X                note_cleanup ();
  907. X                n = next_response (respnum);
  908. X                if (n == -1)
  909. X                    return (which_base(respnum));
  910. X
  911. X                respnum = n;
  912. X                goto restart;
  913. X
  914. X            case 'N':    /* next unread article */
  915. X                n = next_unread(next_response(respnum));
  916. X                if (n == -1)
  917. X                    info_message(txt_no_next_unread_art);
  918. X                else {
  919. X                    note_cleanup();
  920. X                    respnum = n;
  921. X                    goto restart;
  922. X                }
  923. X                break;
  924. X
  925. X            case 'o':    /* output art/thread/tagged arts to printer */
  926. X                if (prompt_yn (LINES, txt_print_yn, 'y')) {
  927. X                    feed_articles (FEED_PRINT, PAGE_LEVEL, "Print", respnum, group_path);
  928. X                }
  929. X                break;
  930. X
  931. X            case 'p':    /* previous article */
  932. X                note_cleanup ();
  933. X                n = prev_response (respnum);
  934. X                if (n == -1)
  935. X                    return (which_resp (respnum));
  936. X
  937. X                respnum = n;
  938. X                goto restart;
  939. X
  940. X            case 'P':    /* previous unread article */
  941. X                n = prev_unread(prev_response(respnum));
  942. X                if (n == -1)
  943. X                    info_message(txt_no_prev_unread_art);
  944. X                else {
  945. X                    note_cleanup();
  946. X                    respnum = n;
  947. X                    goto restart;
  948. X                }
  949. X                break;
  950. X
  951. X            case 'q':    /* quit */
  952. X                if (prompt_yn (LINES, txt_quit, 'y')) {
  953. X                    return -2;
  954. X                }
  955. X                break;
  956. X    
  957. X            case 'r':    /* reply to author through mail */
  958. X                mail_to_author (FALSE);
  959. X                redraw_page (respnum, group);
  960. X                break;
  961. X
  962. X            case 'R':    /* reply to author, copy text */
  963. X                mail_to_author (TRUE);
  964. X                redraw_page (respnum, group);
  965. X                break;
  966. X
  967. X            case 's':    /* save article/thread/tagged articles */
  968. X                feed_articles (FEED_SAVE, PAGE_LEVEL, "Save", respnum, group_path);
  969. X                break;
  970. X
  971. X            case 't':    /* return to group selection page */
  972. X                note_cleanup ();
  973. X                if (kill_state == KILLING) {
  974. X                    if (kill_articles) {
  975. X                        kill_any_articles (group);
  976. X                        reload_index_file (group, TRUE);    /* kill arts */
  977. X                    } else {
  978. X                        reload_index_file (group, FALSE);    /* unkill arts */
  979. X                    }
  980. X                }
  981. X                update_newsrc (group, my_group[cur_groupnum]);
  982. X                fix_new_highest (cur_groupnum);
  983. X                return -1;
  984. X
  985. X            case 'T':    /* tag/untag article for saving */
  986. X                if (arts[respnum].tagged) {
  987. X                    arts[respnum].tagged = 0;
  988. X                    info_message (txt_untagged_art);
  989. X                } else {
  990. X                    arts[respnum].tagged = ++num_of_tagged_files;
  991. X                    info_message (txt_tagged_art);
  992. X                }
  993. X                break;
  994. X
  995. X            case 'v':
  996. X                info_message (cvers);
  997. X                break;
  998. X
  999. X            case 'w':    /* post a basenote */
  1000. X                if (post_base (group)) {
  1001. X                    update_newsrc (group, my_group[cur_groupnum]);
  1002. X                    index_group (group, group_path);
  1003. X                    read_newsrc_line (group);
  1004. X                    redraw_page (respnum, group);
  1005. X                }
  1006. X                break;
  1007. X
  1008. X            case 'W':    /* display messages posted by user */
  1009. X                if (user_posted_messages ()) {
  1010. X                    redraw_page(respnum, group);
  1011. X                }
  1012. X                break;
  1013. X
  1014. X            case 'z':    /* mark article as unread (to return) */
  1015. X                arts[respnum].unread = ART_WILL_RETURN;
  1016. X                info_message(txt_art_marked_as_unread);
  1017. X                break;
  1018. X
  1019. X            default:
  1020. X                info_message(txt_bad_command);
  1021. X        }
  1022. X    }
  1023. X}
  1024. X
  1025. X
  1026. Xvoid redraw_page (respnum, group)
  1027. X    int respnum;
  1028. X    char *group;
  1029. X{
  1030. X
  1031. X    if (note_page == NOTE_UNAVAIL) {
  1032. X        ClearScreen ();
  1033. X        printf (txt_art_unavailable, arts[respnum].artnum);
  1034. X        fflush (stdout);
  1035. X    } else if (note_page > 0) {
  1036. X        note_page--;
  1037. X        fseek (note_fp, note_mark[note_page], 0);
  1038. X        show_note_page (respnum, group);
  1039. X    }
  1040. X}
  1041. X
  1042. X
  1043. Xvoid show_note_page (respnum, group)
  1044. X    int respnum;
  1045. X    char *group;
  1046. X{
  1047. X    char buf[LEN+1];
  1048. X    char buf2[LEN+50];
  1049. X    char *p, *q;
  1050. X    int i, j;
  1051. X    int ctrl_L;        /* form feed character detected */
  1052. X
  1053. X    ClearScreen();
  1054. X
  1055. X    note_line = 1;
  1056. X
  1057. X    if (note_page == 0)
  1058. X        show_first_header (respnum, group);
  1059. X    else
  1060. X        show_cont_header (respnum);
  1061. X
  1062. X    ctrl_L = FALSE;
  1063. X    while (note_line < LINES) {
  1064. X        if (fgets(buf, LEN, note_fp) == NULL) {
  1065. X            note_end = TRUE;
  1066. X            break;
  1067. X        }
  1068. X
  1069. X        buf[LEN-1] = '\0';
  1070. X        if (rotate)
  1071. X            for (p = buf, q = buf2;
  1072. X                    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  1073. X                if (*p == '\b' && q > buf2) {
  1074. X                    q--;
  1075. X                } else if (*p == 12) {        /* ^L */
  1076. X                    *q++ = '^';
  1077. X                    *q++ = 'L';
  1078. X                    ctrl_L = TRUE;
  1079. X                } else if (*p == '\t') {
  1080. X                    i = q - buf2;
  1081. X                    j = (i|7) + 1;
  1082. X
  1083. X                    while (i++ < j)
  1084. X                        *q++ = ' ';
  1085. X                } else if (((*p) & 0x7F) < 32) {
  1086. X                    *q++ = '^';
  1087. X                    *q++ = ((*p) & 0x7F) + '@';
  1088. X                } else if (*p >= 'A' && *p <= 'Z')
  1089. X                    *q++ = 'A' + (*p - 'A' + rotate) % 26;
  1090. X                else if (*p >= 'a' && *p <= 'z')
  1091. X                    *q++ = 'a' + (*p - 'a' + rotate) % 26;
  1092. X                else
  1093. X                    *q++ = *p;
  1094. X            }
  1095. X        else
  1096. X            for (p = buf, q = buf2;
  1097. X                    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  1098. X                if (*p == '\b' && q > buf2) {
  1099. X                    q--;
  1100. X                } else if (*p == 12) {        /* ^L */
  1101. X                    *q++ = '^';
  1102. X                    *q++ = 'L';
  1103. X                    ctrl_L = TRUE;
  1104. X                } else if (*p == '\t') {
  1105. X                    i = q - buf2;
  1106. X                    j = (i|7) + 1;
  1107. X
  1108. X                    while (i++ < j)
  1109. X                        *q++ = ' ';
  1110. X                } else if (((*p) & 0x7F) < 32) {
  1111. X                    *q++ = '^';
  1112. X                    *q++ = ((*p) & 0x7F) + '@';
  1113. X                } else
  1114. X                    *q++ = *p;
  1115. X            }
  1116. X
  1117. X        *q = '\0';
  1118. X
  1119. X        printf("%s\r\n", buf2);
  1120. X
  1121. X        note_line += ((int) strlen (buf2) / COLS) + 1;
  1122. X
  1123. X        if (ctrl_L) {
  1124. X            break;
  1125. X        }
  1126. X    }
  1127. X
  1128. X    note_mark[++note_page] = ftell(note_fp);
  1129. X
  1130. X    if (note_end) {
  1131. X        MoveCursor(LINES, MORE_POS-(5+BLANK_PAGE_COLS));
  1132. X        StartInverse();    
  1133. X        if (arts[respnum].thread != -1) {
  1134. X            printf (txt_next_resp);
  1135. X            fflush (stdout);
  1136. X        } else {
  1137. X            printf (txt_last_resp);
  1138. X            fflush (stdout);
  1139. X        }
  1140. X        EndInverse();
  1141. X    } else {
  1142. X        if (note_size > 0) {
  1143. X            draw_percent_mark (note_mark[note_page], note_size);
  1144. X        } else {
  1145. X            MoveCursor(LINES, MORE_POS-BLANK_PAGE_COLS);
  1146. X            StartInverse();    
  1147. X            printf(txt_more);
  1148. X            fflush (stdout);
  1149. X            EndInverse();
  1150. X        }
  1151. X    }
  1152. X    MoveCursor(LINES, 0);
  1153. X}
  1154. X
  1155. X
  1156. Xvoid show_first_header (respnum, group)
  1157. X    int respnum;
  1158. X    char *group;
  1159. X{
  1160. X    int whichresp;
  1161. X    int x_resp;
  1162. X    char buf[LEN+1];
  1163. X    char tmp[LEN+1];
  1164. X    int pos, i;
  1165. X    int n;
  1166. X
  1167. X    whichresp = which_resp (respnum);
  1168. X    x_resp = nresp (which_base (respnum));
  1169. X
  1170. X    ClearScreen ();
  1171. X
  1172. X    strcpy (buf, note_h_date);
  1173. X    pos = (COLS - (int) strlen (group)) / 2;
  1174. X    for (i = strlen(buf); i < pos; i++)
  1175. X        buf[i] = ' ';
  1176. X    buf[i] = '\0';
  1177. X
  1178. X    strcat (buf, group);
  1179. X
  1180. X    for (i = strlen(buf); i < RIGHT_POS ; i++)
  1181. X        buf[i] = ' ';
  1182. X    buf[i] = '\0';
  1183. X
  1184. X    printf (txt_thread_x_of_n, buf, which_base (respnum) + 1, top_base);
  1185. X
  1186. X    sprintf (buf, txt_art, arts[respnum].artnum);
  1187. X    n = strlen (buf);
  1188. X    fputs (buf, stdout);
  1189. X
  1190. X    strcpy (buf, note_h_subj);
  1191. X/*    buf[RIGHT_POS - 2 - n] = '\0';
  1192. X*/
  1193. X    buf[RIGHT_POS - 2 - n -1] = '\0';
  1194. X
  1195. X    pos = ((COLS - (int) strlen (buf)) / 2) - 2;
  1196. X
  1197. X    if (pos > n) {
  1198. X        MoveCursor (1, pos);
  1199. X    } else {
  1200. X        MoveCursor (1, n);
  1201. X    }
  1202. X
  1203. X    StartInverse ();
  1204. X    fputs (buf, stdout);
  1205. X    EndInverse ();
  1206. X
  1207. X    MoveCursor (1, RIGHT_POS);
  1208. X    if (whichresp)
  1209. X        printf (txt_resp_x_of_n, whichresp, x_resp);
  1210. X    else {
  1211. X        if (x_resp == 0)
  1212. X            printf (txt_no_resp);
  1213. X        else if (x_resp == 1)
  1214. X            printf (txt_1_resp);
  1215. X        else
  1216. X            printf (txt_x_resp, x_resp);
  1217. X    }
  1218. X
  1219. X    if (*note_h_org)
  1220. X        sprintf (tmp, txt_s_at_s, note_full_name, note_h_org);
  1221. X    else
  1222. X        strcpy (tmp, note_full_name);
  1223. X
  1224. X    tmp[LEN] = '\0';
  1225. X
  1226. X    sprintf (buf, "%s  ", note_from_addr);
  1227. X
  1228. X    pos = COLS - 1 - (int) strlen(tmp);
  1229. X    if ((int) strlen (buf) + (int) strlen (tmp) >= COLS - 1) {
  1230. X        strncat (buf, tmp, COLS - 1 - (int) strlen(buf));
  1231. X        buf[COLS - 1] = '\0';
  1232. X    } else {
  1233. X        for (i = strlen(buf); i < pos; i++)
  1234. X            buf[i] = ' ';
  1235. X        buf[i] = '\0';
  1236. X        strcat (buf, tmp);
  1237. X    }
  1238. X    printf ("%s\r\n\r\n", buf);
  1239. X
  1240. X    note_line += 4;
  1241. X}
  1242. X
  1243. X
  1244. Xvoid show_cont_header (respnum)
  1245. X    int respnum;
  1246. X{
  1247. X    int whichresp;
  1248. X    int whichbase;
  1249. X    char buf[LEN+1];
  1250. X
  1251. X    whichresp = which_resp (respnum);
  1252. X    whichbase = which_base (respnum);
  1253. X
  1254. X    assert (whichbase < top_base);
  1255. X
  1256. X    if (whichresp)
  1257. X        sprintf(buf, txt_thread_resp_page,
  1258. X            whichbase + 1,
  1259. X            top_base,
  1260. X            whichresp,
  1261. X            note_page + 1,
  1262. X            note_h_subj);
  1263. X    else
  1264. X        sprintf(buf, txt_thread_page,
  1265. X            whichbase + 1,
  1266. X            top_base,
  1267. X            note_page + 1,
  1268. X            note_h_subj);
  1269. X
  1270. X    buf[COLS] = '\0';
  1271. X    printf("%s\r\n\r\n", buf);
  1272. X
  1273. X    note_line += 2;
  1274. X}
  1275. X
  1276. X
  1277. Xvoid open_note (art, group_path)
  1278. X    long art;
  1279. X    char *group_path;
  1280. X{
  1281. X    char buf[1025];
  1282. X    char *p;
  1283. X
  1284. X    note_page = 0;
  1285. X
  1286. X    if ((note_fp = open_art_fp (group_path, art)) == NULL) {
  1287. X        note_page = NOTE_UNAVAIL;
  1288. X        return;
  1289. X    }
  1290. X
  1291. X    note_h_from[0] = '\0';
  1292. X    note_h_path[0] = '\0';
  1293. X    note_h_subj[0] = '\0';
  1294. X    note_h_org[0] = '\0';
  1295. X    note_h_date[0] = '\0';
  1296. X    note_h_newsgroups[0] = '\0';
  1297. X    note_h_messageid[0] = '\0';
  1298. X    note_h_distrib[0] = '\0';
  1299. X    note_h_followup[0] = '\0';
  1300. X
  1301. X    while (fgets(buf, 1024, note_fp) != NULL) {
  1302. X        buf[1024] = '\0';
  1303. X
  1304. X        for (p=buf ; *p && *p != '\n' ; p++) {
  1305. X            if (((*p) & 0x7F) < 32)
  1306. X                *p = ' ';
  1307. X        }
  1308. X        *p = '\0';
  1309. X        
  1310. X        if (*buf == '\0')
  1311. X            break;
  1312. X
  1313. X        if (strncmp(buf, "From: ", 6) == 0) {
  1314. X            strcpy(note_h_from, &buf[6]);
  1315. X            note_h_from[LEN-1] = '\0';
  1316. X        } else if (strncmp(buf, "Path: ", 6) == 0) {
  1317. X            strcpy(note_h_path, &buf[6]);
  1318. X            note_h_path[LEN-1] = '\0';
  1319. X        } else if (strncmp(buf, "Subject: ", 9) == 0) {
  1320. X            strcpy(note_h_subj, &buf[9]);
  1321. X            note_h_subj[LEN-1] = '\0';
  1322. X        } else if (strncmp(buf, "Organization: ", 14) == 0) {
  1323. X            strcpy(note_h_org, &buf[14]);
  1324. X            note_h_org[LEN-1] = '\0';
  1325. X        } else if (strncmp(buf, "Date: ", 6) == 0) {
  1326. X            strcpy(note_h_date, &buf[6]);
  1327. X            note_h_date[LEN-1] = '\0';
  1328. X        } else if (strncmp(buf, "Newsgroups: ", 12) == 0) {
  1329. X            strcpy(note_h_newsgroups, &buf[12]);
  1330. X            note_h_newsgroups[LEN-1] = '\0';
  1331. X        } else if (strncmp(buf, "Message-ID: ", 12) == 0) {
  1332. X            strcpy(note_h_messageid, &buf[12]);
  1333. X            note_h_messageid[LEN-1] = '\0';
  1334. X        } else if (strncmp(buf, "Distribution: ", 14) == 0) {
  1335. X            strcpy(note_h_distrib, &buf[14]);
  1336. X            note_h_distrib[LEN-1] = '\0';
  1337. X        } else if (strncmp(buf, "Followup-To: ", 13) == 0) {
  1338. X            strcpy(note_h_followup, &buf[13]);
  1339. X            note_h_followup[LEN-1] = '\0';
  1340. X        }
  1341. X    }
  1342. X
  1343. X    note_page = 0;
  1344. X    note_mark[0] = ftell (note_fp);
  1345. X
  1346. X    parse_from (note_h_from, note_from_addr, note_full_name);
  1347. X    note_end = FALSE;
  1348. X
  1349. X    return;
  1350. X}
  1351. X
  1352. X
  1353. Xvoid note_cleanup()
  1354. X{
  1355. X    if (note_page != NOTE_UNAVAIL)
  1356. X        fclose(note_fp);
  1357. X}
  1358. X
  1359. X
  1360. Xint prompt_response(ch, respnum)
  1361. X    int respnum;
  1362. X{
  1363. X    int num;
  1364. X
  1365. X    clear_message ();
  1366. X
  1367. X    if ((num = parse_num (ch, txt_read_resp)) == -1) {
  1368. X        clear_message ();
  1369. X        return -1;
  1370. X    }
  1371. X
  1372. X    return choose_resp (which_base (respnum), num);
  1373. X}
  1374. X
  1375. X/*
  1376. X *  return response number n from thread i
  1377. X */
  1378. X
  1379. Xint choose_resp (i, n)
  1380. X    int i;
  1381. X    int n;
  1382. X{
  1383. X    int j;
  1384. X
  1385. X    j = base[i];
  1386. X
  1387. X    while (n-- && arts[j].thread >= 0) {
  1388. X        j = arts[j].thread;
  1389. X    }
  1390. X
  1391. X    return j;
  1392. X}
  1393. X
  1394. X
  1395. X/*
  1396. X *  Parse various From: lines into the component mail addresses and
  1397. X *  real names
  1398. X */
  1399. X
  1400. Xvoid parse_from (str, addr, name)
  1401. X    char *str;
  1402. X    char *addr;
  1403. X    char *name;
  1404. X{
  1405. X    char *p;
  1406. X    
  1407. X    for (p=str ; *p ; p++) {
  1408. X        if (((*p) & 0x7F) < 32)
  1409. X            *p = ' ';
  1410. X    }
  1411. X
  1412. X    while (*str && *str != ' ')
  1413. X        *addr++ = *str++;
  1414. X    *addr = '\0';
  1415. X    if (*str++ == ' ') {
  1416. X        if (*str++ == '(') {
  1417. X            if (*str == '"')
  1418. X                str++;  /* Kill "quotes around names"         */
  1419. X                    /* But don't touch quotes inside the  */
  1420. X                    /* Name (that's what that nonsense    */
  1421. X                    /* below is for                  */
  1422. X            while (*str && *str != ')' && !(*str=='"'&&str[1]==')'))
  1423. X                *name++ = *str++;
  1424. X        }
  1425. X    }
  1426. X    *name = '\0';
  1427. X}
  1428. X
  1429. X
  1430. X/*
  1431. X *  Find the previous response.  Go to the last response in the previous
  1432. X *  thread if we go past the beginning of this thread.
  1433. X */
  1434. X
  1435. Xint prev_response (n)
  1436. X    int n;
  1437. X{
  1438. X    int resp;
  1439. X    int i;
  1440. X
  1441. X    resp = which_resp (n);
  1442. X
  1443. X    if (resp > 0)
  1444. X        return choose_resp (which_base (n), resp-1);
  1445. X
  1446. X    i = which_base (n) - 1;
  1447. X
  1448. X    if (i < 0)
  1449. X        return -1;
  1450. X
  1451. X    return choose_resp (i, nresp (i));
  1452. X}
  1453. X
  1454. X
  1455. X/*
  1456. X *  Find the next response.  Go to the next basenote if there
  1457. X *  are no more responses in this thread
  1458. X */
  1459. X
  1460. Xint next_response (n)
  1461. X    int n;
  1462. X{
  1463. X    int i;
  1464. X
  1465. X    if (arts[n].thread >= 0)
  1466. X        return arts[n].thread;
  1467. X
  1468. X    i = which_base (n) + 1;
  1469. X
  1470. X    if (i >= top_base)
  1471. X        return -1;
  1472. X
  1473. X    return base[i];
  1474. X}
  1475. X
  1476. X
  1477. X/*
  1478. X *  Given a respnum (index into arts[]), find the respnum of the
  1479. X *  next basenote
  1480. X */
  1481. X
  1482. Xint next_basenote (n)
  1483. X    int n;
  1484. X{
  1485. X    int i;
  1486. X
  1487. X    i = which_base (n) + 1;
  1488. X    if (i >= top_base)
  1489. X        return -1;
  1490. X
  1491. X    return base[i];
  1492. X}
  1493. X
  1494. X
  1495. Xvoid yank_to_addr (orig, addr)
  1496. X    char *orig;
  1497. X    char *addr;
  1498. X{
  1499. X    char *p;
  1500. X
  1501. X    for (p = orig; *p; p++)
  1502. X        if (((*p) & 0x7F) < 32)
  1503. X            *p = ' ';
  1504. X
  1505. X    while (*addr)
  1506. X        addr++;
  1507. X
  1508. X    while (*orig) {
  1509. X        while (*orig && (*orig == ' ' || *orig == '"' || *orig == ','))
  1510. X            orig++;
  1511. X        *addr++ = ' ';
  1512. X        while (*orig && (*orig != ' ' && *orig != ',' && *orig != '"'))
  1513. X            *addr++ = *orig++;
  1514. X        while (*orig && (*orig == ' ' || *orig == '"' || *orig == ','))
  1515. X            orig++;
  1516. X        if (*orig == '(') {
  1517. X            while (*orig && *orig != ')')
  1518. X                orig++;
  1519. X            if (*orig == ')')
  1520. X                orig++;
  1521. X        }
  1522. X    }
  1523. X    *addr = '\0';
  1524. X}
  1525. X
  1526. X
  1527. Xint show_last_page ()
  1528. X{
  1529. X    char buf[LEN+1];
  1530. X    char buf2[LEN+50];
  1531. X    char *p, *q;
  1532. X    int ctrl_L;        /* form feed character detected */
  1533. X    int i, j;
  1534. X    
  1535. X    if (note_end) {
  1536. X        return FALSE;
  1537. X    }
  1538. X
  1539. X    while (! note_end) {
  1540. X        note_line = 1;
  1541. X        ctrl_L = FALSE;
  1542. X
  1543. X        if (note_page == 0) {
  1544. X            note_line += 4;
  1545. X        } else {
  1546. X            note_line += 2;
  1547. X        }
  1548. X        while (note_line < LINES) {
  1549. X            if (fgets(buf, LEN, note_fp) == NULL) {
  1550. X                note_end = TRUE;
  1551. X                break;
  1552. X            }
  1553. X            buf[LEN-1] = '\0';
  1554. X            for (p = buf, q = buf2;    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  1555. X                if (*p == '\b' && q > buf2) {
  1556. X                    q--;
  1557. X                } else if (*p == 12) {        /* ^L */
  1558. X                    *q++ = '^';
  1559. X                    *q++ = 'L';
  1560. X                    ctrl_L = TRUE;
  1561. X                } else if (*p == '\t') {
  1562. X                    i = q - buf2;
  1563. X                    j = (i|7) + 1;
  1564. X
  1565. X                    while (i++ < j) {
  1566. X                        *q++ = ' ';
  1567. X                    }
  1568. X                } else if (((*p) & 0x7F) < 32) {
  1569. X                    *q++ = '^';
  1570. X                    *q++ = ((*p) & 0x7F) + '@';
  1571. X                } else {
  1572. X                    *q++ = *p;
  1573. X                }
  1574. X            }
  1575. X            *q = '\0';
  1576. X            note_line += ((int) strlen (buf2) / COLS) + 1;
  1577. X
  1578. X            if (ctrl_L) {
  1579. X                break;
  1580. X            }
  1581. X        }
  1582. X        if (! note_end) {
  1583. X            note_mark[++note_page] = ftell(note_fp);
  1584. X        }
  1585. X    }
  1586. X    fseek (note_fp, note_mark[note_page], 0);
  1587. X    return TRUE;
  1588. X}
  1589. SHAR_EOF
  1590. $TOUCH -am 0903095091 page.c &&
  1591. chmod 0600 page.c ||
  1592. echo "restore of page.c failed"
  1593. set `wc -c page.c`;Wc_c=$1
  1594. if test "$Wc_c" != "23540"; then
  1595.     echo original size 23540, current size $Wc_c
  1596. fi
  1597. # ============= patchlevel.h ==============
  1598. echo "x - extracting patchlevel.h (Text)"
  1599. sed 's/^X//' << 'SHAR_EOF' > patchlevel.h &&
  1600. X#define PATCHLEVEL    1
  1601. SHAR_EOF
  1602. $TOUCH -am 0903095091 patchlevel.h &&
  1603. chmod 0600 patchlevel.h ||
  1604. echo "restore of patchlevel.h failed"
  1605. set `wc -c patchlevel.h`;Wc_c=$1
  1606. if test "$Wc_c" != "21"; then
  1607.     echo original size 21, current size $Wc_c
  1608. fi
  1609. # ============= post.c ==============
  1610. echo "x - extracting post.c (Text)"
  1611. sed 's/^X//' << 'SHAR_EOF' > post.c &&
  1612. X/*
  1613. X *  Project   : tin - a visual threaded usenet newsreader
  1614. X *  Module    : post.c
  1615. X *  Author    : I.Lea
  1616. X *  Created   : 01-04-91
  1617. X *  Updated   : 01-09-91
  1618. X *  Release   : 1.0
  1619. X *  Notes     : mailing/posting/replying & followup routines
  1620. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  1621. X *                You may  freely  copy or  redistribute  this software,
  1622. X *              so  long as there is no profit made from its use, sale
  1623. X *              trade or  reproduction.  You may not change this copy-
  1624. X *              right notice, and it must be included in any copy made
  1625. X */
  1626. X
  1627. X#include    "tin.h"
  1628. X
  1629. Xextern char note_h_distrib[LEN+1];        /* Distribution: */
  1630. Xextern char note_h_followup[LEN+1];        /* Followup-To: */
  1631. Xextern char note_h_from[LEN+1];            /* From:    */
  1632. Xextern char note_h_messageid[LEN+1];    /* Message-ID:    */
  1633. Xextern char note_h_newsgroups[LEN+1];    /* Newsgroups:    */
  1634. Xextern char note_h_subj[LEN+1];            /* Subject:    */
  1635. X
  1636. Xextern char note_from_addr[100];
  1637. Xextern char note_full_name[100];
  1638. X
  1639. Xextern FILE *note_fp;                    /* the body of the current article */
  1640. X
  1641. Xextern long note_mark[MAX_PAGES];        /* ftells on beginnings of pages */
  1642. X
  1643. X
  1644. Xint user_posted_messages ()
  1645. X{
  1646. X    char buf[LEN+1];
  1647. X    FILE *fp;
  1648. X    int ch;
  1649. X    int i;
  1650. X
  1651. X    set_real_uid_gid ();
  1652. X        
  1653. X    if ((fp = fopen (postfile, "r")) != NULL) {
  1654. X        ClearScreen ();
  1655. X        printf("%s\r\n", nice_time());    /* time in upper left */
  1656. X
  1657. X        center_line (1, TRUE, txt_post_history_menu);
  1658. X    
  1659. X        MoveCursor (INDEX_TOP, 0);
  1660. X        for (i=1 ; fgets (buf, LEN, fp) != NULL ; ) {
  1661. X            if (buf[0] != '#') {
  1662. X                buf[strlen (buf)-1] = ' ';
  1663. X                buf[COLS-2] = '\0';
  1664. X                printf ("%s% *s\r\n", buf, (COLS - (int) strlen (buf))-2, " ");
  1665. X                i++;
  1666. X            }
  1667. X            if (i > NOTESLINES) {
  1668. X                center_line (LINES, FALSE, txt_hit_any_key);
  1669. X                if ((ch = ReadCh ()) != ' ') {
  1670. X                    break;
  1671. X                }
  1672. X                clear_message ();
  1673. X                MoveCursor (INDEX_TOP, 0);
  1674. X                i=1;
  1675. X            }
  1676. X        }
  1677. X        fclose (fp);
  1678. X
  1679. X        if (i != 1 && i < NOTESLINES) {
  1680. X            while (i <= NOTESLINES) {
  1681. X                MoveCursor ((INDEX_TOP+i)-1, 0);
  1682. X                CleartoEOLN ();
  1683. X                i++;
  1684. X            }
  1685. X            center_line (LINES, FALSE, txt_hit_any_key);
  1686. X            ch = ReadCh ();
  1687. X        }
  1688. X        clear_note_area ();
  1689. X        set_tin_uid_gid ();
  1690. X        return TRUE;
  1691. X    }
  1692. X    info_message (txt_no_arts_posted);
  1693. X    set_tin_uid_gid ();
  1694. X    return FALSE;
  1695. X}
  1696. X
  1697. X
  1698. Xvoid update_art_posted_file (group, subj)
  1699. X    char *group;
  1700. X    char *subj;
  1701. X{
  1702. X    char buf[LEN+1];
  1703. X    char tmp_post[LEN+1];
  1704. X    FILE *fp, *tmp_fp;
  1705. X    long epoch;
  1706. X    struct tm *tm;
  1707. X
  1708. X    sprintf (tmp_post, "%s.%d", postfile, getpid ());
  1709. X
  1710. X    set_real_uid_gid ();
  1711. X
  1712. X    if ((tmp_fp = fopen (tmp_post, "w")) != NULL) {
  1713. X        time (&epoch);
  1714. X        tm = localtime (&epoch);
  1715. X        fprintf (tmp_fp, "%02d-%02d-%02d  %-32s %-s\n",
  1716. X            tm->tm_mday, tm->tm_mon+1, tm->tm_year, group, subj);
  1717. X        fclose (tmp_fp);
  1718. X    }
  1719. X
  1720. X    if ((tmp_fp = fopen (tmp_post, "a+")) != NULL) {
  1721. X        if ((fp = fopen (postfile, "r")) != NULL) {
  1722. X            while (fgets (buf, LEN, fp) != NULL) {
  1723. X                fprintf (tmp_fp, "%s", buf);
  1724. X            }    
  1725. X            fclose (fp);
  1726. X            rename_file (tmp_post, postfile);
  1727. X        }
  1728. X        fclose (tmp_fp);
  1729. X    }
  1730. X    set_tin_uid_gid ();
  1731. X}
  1732. X
  1733. X/*
  1734. X *  Post an original article (not a followup)
  1735. X */
  1736. X
  1737. Xint post_base (group)
  1738. X    char *group;
  1739. X{
  1740. X    FILE *fp;
  1741. X    char ch;
  1742. X    char ch_default = 'p';
  1743. X    char subj[LEN+1];
  1744. X    char buf[LEN+1];
  1745. X
  1746. X    if (! parse_string (txt_post_subject, subj)) {
  1747. X        clear_message ();
  1748. X        return FALSE;
  1749. X    }    
  1750. X    if (subj[0] == '\0') {
  1751. X        info_message (txt_no_subject);
  1752. X        return FALSE;
  1753. X    }
  1754. X
  1755. X    set_real_uid_gid ();
  1756. X
  1757. X    if ((fp = fopen (dead_article, "w")) == NULL) {
  1758. X        error_message (txt_cannot_open, dead_article);
  1759. X        set_tin_uid_gid ();
  1760. X        return FALSE;
  1761. X    }
  1762. X    chmod (dead_article, 0600);
  1763. X
  1764. X    fprintf (fp, "Subject: %s\n", subj);
  1765. X    fprintf (fp, "Newsgroups: %s\n", group);
  1766. X    fprintf (fp, "Distribution: \n");
  1767. X    if (*my_org)
  1768. X        fprintf (fp, "Organization: %s\n", my_org);
  1769. X    if (*reply_to)
  1770. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1771. X    fprintf (fp, "\n");
  1772. X
  1773. X    add_signature (fp, FALSE);
  1774. X    fclose (fp);
  1775. X
  1776. X    ch = 'e';
  1777. X    while (1) {
  1778. X        switch (ch) {
  1779. X        case 'e':
  1780. X            start_line_offset = 5;
  1781. X            invoke_editor (dead_article);
  1782. X            break;
  1783. X
  1784. X        case 'a':
  1785. X            unlink (dead_article);
  1786. X            clear_message ();
  1787. X            set_tin_uid_gid ();
  1788. X            return FALSE;
  1789. X
  1790. X        case 'p':
  1791. X            wait_message (txt_posting);
  1792. X            if (debug) {
  1793. X                sprintf (buf, "%s/inews -h < %s", INEWSDIR, dead_article);
  1794. X            } else {
  1795. X                sprintf (buf, "%s/inews -h < %s > /dev/null 2>&1",
  1796. X                    INEWSDIR, dead_article);
  1797. X            }
  1798. X            if (invoke_cmd (buf)) {
  1799. X                unlink (dead_article);
  1800. X                info_message (txt_art_posted);
  1801. X                goto post_base_done;
  1802. X            } else {
  1803. X                sprintf (buf, txt_art_rejected, dead_article);
  1804. X                info_message (buf);
  1805. X                set_tin_uid_gid ();
  1806. X                return FALSE;
  1807. X            }
  1808. X        }
  1809. X
  1810. X        do {
  1811. X            sprintf (msg, "%s%c", txt_abort_edit_post, ch_default);
  1812. X            wait_message (msg);
  1813. X            MoveCursor (LINES, (int) strlen (txt_abort_edit_post));
  1814. X            if ((ch = ReadCh ()) == CR)
  1815. X                ch = ch_default;
  1816. X        } while (ch != 'a' && ch != 'e' && ch != 'p');
  1817. X    }
  1818. X
  1819. Xpost_base_done:
  1820. X    set_tin_uid_gid ();
  1821. X    update_art_posted_file (group, subj);
  1822. X    return TRUE;
  1823. X}
  1824. X
  1825. X
  1826. Xint post_response (group, respnum)
  1827. X    char *group;
  1828. X    int respnum;
  1829. X{
  1830. X    FILE *fp;
  1831. X    char ch, *ptr;
  1832. X    char ch_default = 'p';
  1833. X    char buf[LEN+1];
  1834. X
  1835. X    start_line_offset = 6;
  1836. X
  1837. X    if (*note_h_followup && strcmp (note_h_followup, "poster") == 0) {
  1838. X        clear_message ();
  1839. X        if (! prompt_yn (LINES, txt_resp_to_poster, 'y')) {
  1840. X            return FALSE;
  1841. X        }
  1842. X        *note_h_followup = '\0';
  1843. X    } else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
  1844. X        MoveCursor (LINES/2, 0);
  1845. X        CleartoEOS ();
  1846. X        center_line ((LINES/2)+2, TRUE, txt_resp_redirect);
  1847. X        MoveCursor ((LINES/2)+4, 0);
  1848. X
  1849. X        printf ("    ");
  1850. X        ptr = note_h_followup;
  1851. X        while (*ptr) {
  1852. X            if (*ptr != ',') {
  1853. X                putc (*ptr, stdout);
  1854. X            } else {
  1855. X                printf ("\r\n    ");
  1856. X            }
  1857. X            fflush (stdout);
  1858. X            ptr++;
  1859. X        }
  1860. X
  1861. X        if (! prompt_yn (LINES, txt_continue, 'y')) {
  1862. X            return FALSE;
  1863. X        }
  1864. X    }
  1865. X
  1866. X    set_real_uid_gid ();
  1867. X
  1868. X    if ((fp = fopen (dead_article, "w")) == NULL) {
  1869. X        error_message (txt_cannot_open, dead_article);
  1870. X        set_tin_uid_gid ();
  1871. X        return FALSE;
  1872. X    }
  1873. X    chmod (dead_article, 0600);
  1874. X
  1875. X    fprintf (fp, "Subject: Re: %s\n", eat_re (note_h_subj));
  1876. X
  1877. X    if (*note_h_followup && strcmp(note_h_followup, "poster") != 0)
  1878. X        fprintf (fp, "Newsgroups: %s\n", note_h_followup);
  1879. X    else
  1880. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  1881. X
  1882. X    if (*my_org) {
  1883. X        fprintf (fp, "Organization: %s\n", my_org);
  1884. X    }
  1885. X
  1886. X    if (*reply_to) {
  1887. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1888. X        start_line_offset++;
  1889. X    }
  1890. X
  1891. X    if (note_h_distrib != '\0') {
  1892. X        fprintf (fp, "Distribution: %s\n", note_h_distrib);
  1893. X        start_line_offset++;
  1894. X    }
  1895. X
  1896. X    fprintf (fp, "References: %s\n", note_h_messageid);
  1897. X    fprintf (fp, "\n");
  1898. X
  1899. X    if (respnum) {        /* if "copy_text" */
  1900. X        if (note_h_from[0]) {     
  1901. X            fprintf (fp, txt_writes, note_h_from);
  1902. X        }
  1903. X        fseek (note_fp, note_mark[0], 0);
  1904. X        copy_fp (note_fp, fp, "> ");
  1905. X    }
  1906. X
  1907. X    add_signature (fp, FALSE);
  1908. X    fclose (fp);
  1909. X
  1910. X    ch = 'e';
  1911. X    while (1) {
  1912. X        switch (ch) {
  1913. X        case 'e':
  1914. X            invoke_editor (dead_article);
  1915. X            break;
  1916. X
  1917. X        case 'a':
  1918. X            unlink (dead_article);
  1919. X            clear_message ();
  1920. X            set_tin_uid_gid ();
  1921. X            return FALSE;
  1922. X
  1923. X        case 'p':
  1924. X            wait_message (txt_posting);
  1925. X            if (debug) {
  1926. X                sprintf (buf, "%s/inews -h < %s", INEWSDIR, dead_article);
  1927. X            } else {
  1928. X                sprintf (buf, "%s/inews -h < %s > /dev/null 2>&1",
  1929. X                    INEWSDIR, dead_article);
  1930. X            }
  1931. X            if (invoke_cmd (buf)) {
  1932. X                unlink (dead_article);
  1933. X                info_message (txt_art_posted);
  1934. X                goto post_response_done;
  1935. X            } else {
  1936. X                sprintf (buf, txt_art_rejected, dead_article);
  1937. X                info_message (buf);
  1938. X                set_tin_uid_gid ();
  1939. X                return FALSE;
  1940. X            }
  1941. X        }
  1942. X
  1943. X        do {
  1944. X            sprintf (msg, "%s%c", txt_abort_edit_post, ch_default);
  1945. X            wait_message (msg);
  1946. X            MoveCursor(LINES, strlen (txt_abort_edit_post));
  1947. X            if ((ch = ReadCh()) == CR)
  1948. X                ch = ch_default;
  1949. X        } while (ch != 'a' && ch != 'e' && ch != 'p');
  1950. X    }
  1951. X
  1952. Xpost_response_done:
  1953. X    set_tin_uid_gid ();
  1954. X
  1955. X    if (*note_h_followup && strcmp(note_h_followup, "poster") != 0)
  1956. X        update_art_posted_file (note_h_followup, note_h_subj);
  1957. X    else
  1958. X        update_art_posted_file (note_h_newsgroups, note_h_subj);
  1959. X
  1960. X    return TRUE;
  1961. X}
  1962. X
  1963. X
  1964. Xint mail_to_someone (single_article, address)
  1965. X    int single_article;
  1966. X    char *address;
  1967. X{
  1968. X    char nam[100];
  1969. X    char ch, ch_default = 's';
  1970. X    char buf[LEN+1];
  1971. X    char mail_to[LEN+1];
  1972. X    FILE *fp;
  1973. X    int redraw_screen = FALSE;
  1974. X    
  1975. X    if (single_article) {
  1976. X        if (! parse_string (txt_mail_art_to, mail_to)) {
  1977. X            clear_message ();
  1978. X            return (redraw_screen);
  1979. X        }
  1980. X        if (mail_to[0] == '\0') {
  1981. X            info_message (txt_no_mail_address);
  1982. X            return (redraw_screen);
  1983. X        }
  1984. X    } else {
  1985. X        strcpy (mail_to, address);
  1986. X        clear_message ();
  1987. X    }
  1988. X    
  1989. X    set_real_uid_gid ();
  1990. X
  1991. X    sprintf(nam, "%s/.letter", homedir);
  1992. X    if ((fp = fopen(nam, "w")) == NULL) {
  1993. X        error_message (txt_cannot_open, nam);
  1994. X        set_tin_uid_gid ();
  1995. X        return (redraw_screen);
  1996. X    }
  1997. X    chmod (nam, 0600);
  1998. X
  1999. X    fprintf (fp, "To: %s\n", mail_to);
  2000. X    fprintf (fp, "Subject: %s\n", note_h_subj);
  2001. X    if (*note_h_followup)
  2002. X        fprintf (fp, "Newsgroups: %s\n\n", note_h_followup);
  2003. X    else
  2004. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  2005. X    if (*my_org)
  2006. X        fprintf (fp, "Organization: %s\n", my_org);
  2007. X    if (*reply_to)
  2008. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  2009. X    fputs ("\n", fp);
  2010. X    
  2011. X    fseek (note_fp, 0L, 0);
  2012. X    copy_fp (note_fp, fp, "");
  2013. X
  2014. X    add_signature (fp, TRUE);
  2015. X    fclose (fp);
  2016. X    
  2017. X    while (1) {
  2018. X        do {
  2019. X            my_strncpy (buf, note_h_subj, COLS-30);
  2020. X            sprintf (msg, "%s [%s]: %c", txt_abort_edit_send, buf, ch_default);
  2021. X            wait_message (msg);
  2022. X            MoveCursor (LINES, strlen (msg)-1);
  2023. X            if ((ch = ReadCh ()) == CR)
  2024. X                ch = ch_default;
  2025. X        } while (ch != 'a' && ch != 'e' && ch != 's');
  2026. X
  2027. X        switch (ch) {
  2028. X        case 'e':
  2029. X            start_line_offset = 5;
  2030. X            invoke_editor (nam);
  2031. X            redraw_screen = TRUE;
  2032. X            break;
  2033. X
  2034. X        case 'a':
  2035. X            unlink (nam);
  2036. X            clear_message ();
  2037. X            set_tin_uid_gid ();
  2038. X            return (redraw_screen);
  2039. X
  2040. X        case 's':
  2041. X/*
  2042. X *  Open letter and get the To: line in case they changed it with
  2043. X *  the editor
  2044. X */
  2045. X            find_new_to (nam, mail_to);
  2046. X            sprintf (msg, txt_mailing_to, mail_to);
  2047. X            wait_message (msg);
  2048. X            sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  2049. X            if (invoke_cmd (buf)) {
  2050. X                info_message (txt_message_sent);
  2051. X                goto mail_to_someone_done;
  2052. X            } else {
  2053. X                error_message (txt_command_failed_s, buf);
  2054. X                break;
  2055. X            }
  2056. X        }
  2057. X    }
  2058. X
  2059. Xmail_to_someone_done:
  2060. X    unlink (nam);
  2061. X    set_tin_uid_gid ();
  2062. X
  2063. X    return (redraw_screen);
  2064. X}
  2065. X
  2066. X
  2067. Xint mail_bug_report ()
  2068. X{
  2069. X    char nam[100];
  2070. X    FILE *fp;
  2071. X    char ch;
  2072. X    char ch_default = 's';
  2073. X    char buf[LEN+1];
  2074. X    char mail_to[LEN+1];
  2075. X    int start_line = 5;
  2076. X    
  2077. X    set_real_uid_gid ();
  2078. X
  2079. X    sprintf (nam, "%s/.bugreport", homedir);
  2080. X    if ((fp = fopen (nam, "w")) == NULL) {
  2081. X        error_message (txt_cannot_open, nam);
  2082. X        set_tin_uid_gid ();
  2083. X        return FALSE;
  2084. X    }
  2085. X    chmod(nam, 0600);
  2086. X
  2087. X    fprintf (fp, "To: %s\n", bug_addr);
  2088. X    fprintf (fp, "Subject: BUG REPORT %s %s PL%d %s\n",    progname,
  2089. X        version, PATCHLEVEL, (compiled_with_nntp ? "(NNTP)" : ""));
  2090. X    if (*my_org) {
  2091. X        fprintf (fp, "Organization: %s\n", my_org);
  2092. X        start_line++;
  2093. X    }
  2094. X    if (*reply_to) {
  2095. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  2096. X        start_line++;
  2097. X    }
  2098. X    fprintf (fp, "\nPlease enter the following information:\n");
  2099. X    fprintf (fp, "1) machine:\n");
  2100. X    fprintf (fp, "2) os type:\n");
  2101. X    fprintf (fp, "\nPlease enter bug/gripe/comment report:\n");
  2102. X
  2103. X    add_signature (fp, TRUE);
  2104. X    fclose (fp);
  2105. X    
  2106. X    ch = 'e';
  2107. X    while (1) {
  2108. X        switch (ch) {
  2109. X        case 'e':
  2110. X            start_line_offset = start_line;
  2111. X            invoke_editor (nam);
  2112. X            break;
  2113. X
  2114. X        case 'a':
  2115. X            unlink (nam);
  2116. X            clear_message ();
  2117. X            set_tin_uid_gid ();
  2118. X            return FALSE;
  2119. X
  2120. X        case 's':
  2121. X            strcpy (mail_to, bug_addr);
  2122. X            find_new_to (nam, mail_to);
  2123. X            sprintf (msg, txt_mailing_to, mail_to);
  2124. X            wait_message (msg);
  2125. X            sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  2126. X            if (invoke_cmd (buf)) {
  2127. X                info_message (txt_message_sent);
  2128. X                goto mail_bug_report_done;
  2129. X            } else {
  2130. X                error_message (txt_command_failed_s, buf);
  2131. X                break;
  2132. X            }
  2133. X        }
  2134. X
  2135. X        do {
  2136. X            sprintf (msg, "%s: %c", txt_abort_edit_send, ch_default);
  2137. X            wait_message (msg);
  2138. X            MoveCursor (LINES, strlen (msg)-1);
  2139. X            if ((ch = ReadCh ()) == CR)
  2140. X                ch = ch_default;
  2141. X        } while (ch != 'a' && ch != 'e' && ch != 's');
  2142. X    }
  2143. X
  2144. Xmail_bug_report_done:
  2145. X    unlink (nam);
  2146. X    set_tin_uid_gid ();
  2147. X
  2148. X    return TRUE;
  2149. X}
  2150. X
  2151. X
  2152. Xint mail_to_author (copy_text)
  2153. X    int copy_text;
  2154. X{
  2155. X    char nam[100];
  2156. X    FILE *fp;
  2157. X    char ch;
  2158. X    char ch_default = 's';
  2159. X    char buf[LEN+1];
  2160. X    char mail_to[LEN+1];
  2161. X
  2162. X    set_real_uid_gid ();
  2163. X
  2164. X    sprintf (nam, "%s/.letter", homedir);
  2165. X    if ((fp = fopen (nam, "w")) == NULL) {
  2166. X        error_message (txt_cannot_open, nam);
  2167. X        set_tin_uid_gid ();
  2168. X        return FALSE;
  2169. X    }
  2170. X    chmod (nam, 0600);
  2171. X
  2172. X    fprintf (fp, "To: %s%s (%s)\n", note_from_addr, add_addr, note_full_name);
  2173. X    fprintf (fp, "Subject: Re: %s\n", eat_re(note_h_subj) );
  2174. X    fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  2175. X    if (*my_org)
  2176. X        fprintf (fp, "Organization: %s\n", my_org);
  2177. X    if (*reply_to)
  2178. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  2179. X    fputs ("\n", fp);
  2180. X
  2181. X    if (copy_text) {        /* if "copy_text" */
  2182. X        fprintf (fp, txt_in_art_you_write, note_h_messageid);
  2183. X
  2184. X        fseek (note_fp, note_mark[0], 0);
  2185. X        copy_fp (note_fp, fp, "> ");
  2186. X    }
  2187. X
  2188. X    add_signature (fp, TRUE);
  2189. X    fclose (fp);
  2190. X
  2191. X    ch = 'e';
  2192. X    while (1) {
  2193. X        switch (ch) {
  2194. X        case 'e':
  2195. X            start_line_offset = 5;
  2196. X            invoke_editor (nam);
  2197. X            break;
  2198. X
  2199. X        case 'a':
  2200. X            unlink (nam);
  2201. X            clear_message ();
  2202. X            set_tin_uid_gid ();
  2203. X            return FALSE;
  2204. X
  2205. X        case 's':
  2206. X            strcpy (mail_to, note_from_addr);
  2207. X            find_new_to (nam, mail_to);
  2208. X            sprintf (msg, txt_mailing_to, mail_to);
  2209. X            wait_message (msg);
  2210. X            sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  2211. X            if (invoke_cmd (buf)) {
  2212. X                info_message (txt_message_sent);
  2213. X                goto mail_to_author_done;
  2214. X            } else {
  2215. X                error_message (txt_command_failed_s, buf);
  2216. X                break;
  2217. X            }
  2218. X        }
  2219. X
  2220. X        do {
  2221. X            sprintf (msg, "%s: %c", txt_abort_edit_send, ch_default);
  2222. X            wait_message (msg);
  2223. X            MoveCursor (LINES, strlen (msg)-1);
  2224. X            if ((ch = ReadCh ()) == CR)
  2225. X                ch = ch_default;
  2226. X        } while (ch != 'a' && ch != 'e' && ch != 's');
  2227. X    }
  2228. X
  2229. Xmail_to_author_done:
  2230. X    unlink (nam);
  2231. X    set_tin_uid_gid ();
  2232. X
  2233. X    return TRUE;
  2234. X}
  2235. X
  2236. X/*
  2237. X *  Read a file grabbing the address given for To: and
  2238. X *  sticking it in mail_to
  2239. X */
  2240. X
  2241. Xvoid find_new_to (nam, mail_to)
  2242. X    char *nam;
  2243. X    char *mail_to;
  2244. X{
  2245. X    FILE *fp;
  2246. X    char buf[LEN+1];
  2247. X    char buf2[LEN+1];
  2248. X    char new_mail_to[LEN+1];
  2249. X    char *p;
  2250. X
  2251. X    *new_mail_to = '\0';
  2252. X
  2253. X    if ((fp = fopen(nam, "r")) == NULL) {
  2254. X        fprintf(stderr, txt_cannot_open, nam);
  2255. X        return;
  2256. X    }
  2257. X
  2258. X    while (fgets(buf, 1024, fp) != NULL) {
  2259. X        for (p = buf; *p && *p != '\n'; p++) ;
  2260. X        *p = '\0';
  2261. X
  2262. X        if (*buf == '\0')
  2263. X            break;
  2264. X
  2265. X        if (strncmp(buf, "To: ", 4) == 0) {
  2266. X            strncpy(buf2, &buf[4], LEN);
  2267. X            buf2[LEN-1] = '\0';
  2268. X            yank_to_addr(buf2, new_mail_to);
  2269. X        } else if (strncmp(buf, "Cc: ", 4) == 0) {
  2270. X            strncpy(buf2, &buf[4], LEN);
  2271. X            buf2[LEN-1] = '\0';
  2272. X            yank_to_addr(buf2, new_mail_to);
  2273. X        }
  2274. X    }
  2275. X
  2276. X    fclose(fp);
  2277. X    if (new_mail_to[0] == ' ')
  2278. X        my_strncpy(mail_to, &new_mail_to[1], LEN);
  2279. X    else
  2280. X        my_strncpy(mail_to, new_mail_to, LEN);
  2281. X}
  2282. SHAR_EOF
  2283. $TOUCH -am 0903095091 post.c &&
  2284. chmod 0600 post.c ||
  2285. echo "restore of post.c failed"
  2286. set `wc -c post.c`;Wc_c=$1
  2287. if test "$Wc_c" != "14484"; then
  2288.     echo original size 14484, current size $Wc_c
  2289. fi
  2290. # ============= prompt.c ==============
  2291. echo "x - extracting prompt.c (Text)"
  2292. sed 's/^X//' << 'SHAR_EOF' > prompt.c &&
  2293. X/*
  2294. X *  Project   : tin - a visual threaded usenet newsreader
  2295. X *  Module    : prompt.c
  2296. X *  Author    : R.Skrenta / I.Lea
  2297. X *  Created   : 01-04-91
  2298. X *  Updated   : 10-08-91
  2299. X *  Release   : 1.0
  2300. X *  Notes     :
  2301. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  2302. X *                You may  freely  copy or  redistribute  this software,
  2303. X *              so  long as there is no profit made from its use, sale
  2304. SHAR_EOF
  2305. echo "End of tin1.0 part 5"
  2306. echo "File prompt.c is continued in part 6"
  2307. echo "6" > shar3_seq_.tmp
  2308. exit 0
  2309.  
  2310.  
  2311. --
  2312. NAME   Iain Lea
  2313. EMAIL  norisc!iain@estevax.UUCP  ...!unido!estevax!norisc!iain
  2314. SNAIL  Siemens AG, AUT 922C, Postfach 4848, Nuernberg, Germany
  2315. PHONE  +49-911-895-3853, +49-911-895-3877, +49-911-331963
  2316.