home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume30 / tin / part06 < prev    next >
Encoding:
Text File  |  1992-05-19  |  54.2 KB  |  2,382 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  3. Subject:  v30i006:  tin - threaded full screen newsreader, Part06/14
  4. Message-ID: <1992May20.172436.28850@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8383d745e6ccf160bff79d5c9cf45e2b
  6. Date: Wed, 20 May 1992 17:24:36 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  10. Posting-number: Volume 30, Issue 6
  11. Archive-name: tin/part06
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 29, Issue 19-30
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  group.c post.c
  22. # Wrapped by kent@sparky on Tue May 19 13:38:03 1992
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 6 (of 14)."'
  26. if test -f 'group.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'group.c'\"
  28. else
  29.   echo shar: Extracting \"'group.c'\" \(24125 characters\)
  30.   sed "s/^X//" >'group.c' <<'END_OF_FILE'
  31. X/*
  32. X *  Project   : tin - a threaded Netnews reader
  33. X *  Module    : group.c
  34. X *  Author    : I.Lea & R.Skrenta
  35. X *  Created   : 01-04-91
  36. X *  Updated   : 10-05-92
  37. X *  Notes     :
  38. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  39. X *              You may  freely  copy or  redistribute  this software,
  40. X *              so  long as there is no profit made from its use, sale
  41. X *              trade or  reproduction.  You may not change this copy-
  42. X *              right notice, and it must be included in any copy made
  43. X */
  44. X
  45. X#include    "tin.h"
  46. X
  47. Xextern char cvers[LEN];
  48. Xextern int cur_groupnum;
  49. Xextern int last_resp;        /* page.c */
  50. Xextern int this_resp;        /* page.c */
  51. Xextern int note_page;        /* page.c */
  52. X
  53. Xchar *glob_group;
  54. Xint index_point;
  55. Xint first_subj_on_screen;
  56. Xint last_subj_on_screen;
  57. X
  58. X#ifndef ART_ADJUST    /* what we do here is bizarre */
  59. X#define ART_ADJUST(n)    (show_only_unread \
  60. X                ? ((n) > 1 ? (n) : 0) \
  61. X                : ((n) > 0 ? (n) - 1 : 0))
  62. X#endif
  63. X
  64. Xvoid group_page (group)
  65. X    char *group;
  66. X{
  67. X#ifndef INDEX_DAEMON
  68. X
  69. X    char group_path[LEN];
  70. X    char buf[32];
  71. X    char ch;
  72. X    char *p;
  73. X    int dummy = 0;
  74. X    int flag, i, n;
  75. X    int kill_state;
  76. X    int old_top = 0;
  77. X    int posted;
  78. X    int sav_groupnum;
  79. X    int scroll_lines;
  80. X    long old_artnum = 0L;
  81. X     struct art_stat_t sbuf;
  82. X
  83. X    active[my_group[cur_groupnum]].attribute.read = TRUE;
  84. X
  85. X    glob_group = group;
  86. X    sav_groupnum = cur_groupnum;
  87. X    
  88. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  89. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  90. X        if (*p == '.')
  91. X            *p = '/';
  92. X
  93. X    last_resp = -1;
  94. X    this_resp = -1;
  95. X    index_group (group, group_path);    /* update index file */
  96. X    
  97. X    if (space_mode) {
  98. X        for (i = 0; i < top_base; i++) {
  99. X            if (new_responses (i)) {
  100. X                break;
  101. X            }
  102. X        }
  103. X        if (i < top_base) {
  104. X            index_point = i;
  105. X        } else {
  106. X            index_point = top_base - 1;
  107. X        }
  108. X    } else {
  109. X        index_point = top_base - 1;
  110. X    }
  111. X    if (index_point < 0) {
  112. X        index_point = 0;
  113. X    }
  114. X    
  115. X    clear_note_area ();
  116. X
  117. X    show_group_page (group);
  118. X
  119. X    while (TRUE) {
  120. X        ch = (char) ReadCh ();
  121. X
  122. X        if (ch > '0' && ch <= '9') {    /* 0 goes to basenote */
  123. X            prompt_subject_num (ch, group);
  124. X            continue;
  125. X        } 
  126. X        switch (ch) {
  127. X            case ESC:    /* common arrow keys */
  128. X                switch (get_arrow_key ()) {
  129. X                case KEYMAP_UP:
  130. X                    goto group_up;
  131. X
  132. X                case KEYMAP_DOWN:
  133. X                    goto group_down;
  134. X
  135. X                case KEYMAP_PAGE_UP:
  136. X                    goto group_page_up;
  137. X
  138. X                case KEYMAP_PAGE_DOWN:
  139. X                    goto group_page_down;
  140. X
  141. X                case KEYMAP_HOME:
  142. X                    if (index_point != 0) {
  143. X                        if (0 < first_subj_on_screen) {
  144. X#ifndef USE_CLEARSCREEN
  145. X                            erase_subject_arrow ();
  146. X#endif                    
  147. X                            index_point = 0;
  148. X                            show_group_page (group);
  149. X                        } else {
  150. X                            erase_subject_arrow ();
  151. X                            index_point = 0;
  152. X                            draw_subject_arrow ();
  153. X                        }
  154. X                    }
  155. X                    break;
  156. X                    
  157. X                case KEYMAP_END:
  158. X                    goto end_of_list;
  159. X                }
  160. X                break;
  161. X
  162. X#ifndef NO_SHELL_ESCAPE
  163. X            case '!':
  164. X                shell_escape ();
  165. X                show_group_page (group);
  166. X                break;
  167. X#endif
  168. X
  169. X            case '$':    /* show last page of articles */
  170. Xend_of_list:            
  171. X                if (index_point != top_base - 1) {
  172. X                    if (top_base - 1 > last_subj_on_screen) {
  173. X#ifndef USE_CLEARSCREEN
  174. X                        erase_subject_arrow ();
  175. X#endif                    
  176. X                        index_point = top_base - 1;
  177. X                        show_group_page (group);
  178. X                    } else {
  179. X                        erase_subject_arrow ();
  180. X                        index_point = top_base - 1;
  181. X                        draw_subject_arrow ();
  182. X                    }
  183. X                }
  184. X                break;
  185. X                
  186. X            case '-':    /* go to last viewed article */
  187. X                if (this_resp < 0) {
  188. X                    info_message (txt_no_last_message);
  189. X                    break;
  190. X                }
  191. X                index_point = show_page (this_resp, &dummy, group, group_path);
  192. X                if (index_point < 0) {
  193. X                    space_mode = FALSE;
  194. X                    goto group_done;
  195. X                }
  196. X                clear_note_area ();
  197. X                show_group_page (group);
  198. X                break;
  199. X
  200. X            case '|':    /* pipe article/thread/tagged arts to command */
  201. X                if (index_point >= 0) {
  202. X                    feed_articles (FEED_PIPE, GROUP_LEVEL, "Pipe",
  203. X                        (int) base[index_point], group_path);
  204. X                }
  205. X                break;
  206. X
  207. X            case '/':    /* forward/backward search */
  208. X            case '?':
  209. X                i = (ch == '/');
  210. X                search_subject (i, group);
  211. X                break;
  212. X
  213. X            case '\r':
  214. X            case '\n':    /* read current basenote */
  215. X                if (index_point < 0) {
  216. X                    info_message(txt_no_arts);
  217. X                    break;
  218. X                }
  219. X                i = (int) base[index_point];
  220. X                index_point = show_page (i, &dummy, group, group_path);
  221. X                if (index_point < 0) {
  222. X                    space_mode = FALSE;
  223. X                    goto group_done;
  224. X                }
  225. X                clear_note_area ();
  226. X                show_group_page (group);
  227. X                break;
  228. X
  229. X            case '\t':
  230. X                 space_mode = TRUE;
  231. X
  232. X                if (index_point < 0
  233. X                || (n=next_unread((int) base[index_point]))<0) {
  234. X                    for (i = cur_groupnum+1 ; i < group_top ; i++)
  235. X                        if (unread[i] > 0)
  236. X                            break;
  237. X                    if (i >= group_top)
  238. X                        goto group_done;
  239. X
  240. X                    cur_groupnum = i;
  241. X                    index_point = -3;
  242. X                    goto group_done;
  243. X                }
  244. X                index_point = show_page(n, &dummy, group, group_path);
  245. X                if (index_point < 0)
  246. X                    goto group_done;
  247. X                clear_note_area ();
  248. X                show_group_page(group);
  249. X                break;
  250. X    
  251. X            case ' ':            /* page down */
  252. X            case ctrl('D'):        /* vi style */
  253. X            case ctrl('V'):        /* emacs style */
  254. Xgroup_page_down:
  255. X                if (! top_base) {
  256. X                    break;
  257. X                }
  258. X                if (index_point == top_base - 1) {
  259. X#ifdef NO_LOOP_AROUND
  260. X                    break;
  261. X#else
  262. X                    if (0 < first_subj_on_screen) {
  263. X#    ifndef USE_CLEARSCREEN
  264. X                        erase_subject_arrow ();
  265. X#    endif                    
  266. X                        index_point = 0;
  267. X                        show_group_page (group);
  268. X                    } else {
  269. X                        erase_subject_arrow ();
  270. X                        index_point = 0;
  271. X                        draw_subject_arrow ();
  272. X                    }
  273. X                    break;
  274. X#endif                    
  275. X                }
  276. X                erase_subject_arrow ();
  277. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  278. X                index_point = ((index_point + scroll_lines) / scroll_lines) * scroll_lines;
  279. X                if (index_point >= top_base) {
  280. X                    index_point = (top_base / scroll_lines) * scroll_lines;
  281. X                    if (index_point < top_base - 1) {
  282. X                        index_point = top_base - 1;
  283. X                    }
  284. X                }
  285. X                if (index_point < first_subj_on_screen
  286. X                || index_point >= last_subj_on_screen)
  287. X                    show_group_page (group);
  288. X                else
  289. X                    draw_subject_arrow ();
  290. X                break;
  291. X
  292. X            case ctrl('K'):        /* kill article */
  293. X                 if (index_point < 0) {
  294. X                     info_message (txt_no_arts);
  295. X                    break;
  296. X                }
  297. X                old_top = top;
  298. X                n = (int) base[index_point];
  299. X                old_artnum = arts[n].artnum;
  300. X                if (kill_art_menu (group, (int) base[index_point])) {
  301. X                    kill_any_articles (group);
  302. X                    make_threads (FALSE);
  303. X                    find_base (show_only_unread);
  304. X                    index_point = find_new_pos (old_top, old_artnum, index_point);
  305. X                }
  306. X                show_group_page (group);
  307. X                break;
  308. X
  309. X            case ctrl('L'):        /* redraw screen */
  310. X            case ctrl('R'):
  311. X            case ctrl('W'):
  312. X#ifndef USE_CLEARSCREEN
  313. X                ClearScreen ();
  314. X#endif
  315. X                show_group_page (group);
  316. X                break;
  317. X
  318. X            case ctrl('N'):
  319. X            case 'j':        /* line down */
  320. Xgroup_down:
  321. X                if (! top_base) {
  322. X                    break;
  323. X                }
  324. X                if (index_point + 1 >= top_base) {
  325. X#ifdef NO_LOOP_AROUND
  326. X                    break;
  327. X#else
  328. X                    if (0 < first_subj_on_screen) {
  329. X                        index_point = 0;
  330. X                        show_group_page (group);
  331. X                    } else {
  332. X                        erase_subject_arrow ();
  333. X                        index_point = 0;
  334. X                        draw_subject_arrow ();
  335. X                    }
  336. X                    break;
  337. X#endif                    
  338. X                }
  339. X                if (index_point + 1 >= last_subj_on_screen) {
  340. X#ifndef USE_CLEARSCREEN
  341. X                    erase_subject_arrow();
  342. X#endif                    
  343. X                    index_point++;
  344. X                    show_group_page(group);
  345. X                } else {
  346. X                    erase_subject_arrow();
  347. X                    index_point++;
  348. X                    draw_subject_arrow();
  349. X                }
  350. X                break;
  351. X
  352. X            case ctrl('P'):
  353. X            case 'k':        /* line up */
  354. Xgroup_up:
  355. X                if (! top_base || index_point == 0) {
  356. X#ifdef NO_LOOP_AROUND
  357. X                    break;
  358. X#else
  359. X                    if (top_base > last_subj_on_screen) {
  360. X                        index_point = top_base - 1;
  361. X                        show_group_page (group);
  362. X                    } else {
  363. X                        erase_subject_arrow ();
  364. X                        index_point = top_base - 1;
  365. X                        draw_subject_arrow ();
  366. X                    }
  367. X                    break;
  368. X#endif                    
  369. X                }
  370. X                if (index_point <= first_subj_on_screen) {
  371. X                    index_point--;
  372. X                    show_group_page(group);
  373. X                } else {
  374. X                    erase_subject_arrow();
  375. X                    index_point--;
  376. X                    draw_subject_arrow();
  377. X                }
  378. X                break;
  379. X
  380. X            case ctrl('U'):        /* page up */
  381. X            case 'b':
  382. Xgroup_page_up:
  383. X                if (! top_base) {
  384. X                    break;
  385. X                }
  386. X                if (index_point == 0) {
  387. X#ifdef NO_LOOP_AROUND
  388. X                    break;
  389. X#else
  390. X                    if (top_base > last_subj_on_screen) {
  391. X                        index_point = top_base - 1;
  392. X                        show_group_page (group);
  393. X                    } else {
  394. X                        erase_subject_arrow ();
  395. X                        index_point = top_base - 1;
  396. X                        draw_subject_arrow ();
  397. X                    }
  398. X                    break;
  399. X#endif                    
  400. X                }
  401. X#ifndef USE_CLEARSCREEN
  402. X                clear_message ();
  403. X#endif
  404. X                erase_subject_arrow ();
  405. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  406. X                if ((n = index_point % scroll_lines) > 0) {
  407. X                    index_point = index_point - n;
  408. X                } else {
  409. X                    index_point = ((index_point - scroll_lines) / scroll_lines) * scroll_lines;
  410. X                }
  411. X                if (index_point < 0) {
  412. X                    index_point = 0;
  413. X                }
  414. X                if (index_point < first_subj_on_screen
  415. X                || index_point >= last_subj_on_screen)
  416. X                    show_group_page (group);
  417. X                else
  418. X                    draw_subject_arrow ();
  419. X                break;
  420. X
  421. X            case 'a':    /* author search forward */
  422. X            case 'A':    /* author search backward */
  423. X                if (index_point < 0) {
  424. X                    info_message (txt_no_arts);
  425. X                    break;
  426. X                }
  427. X
  428. X                i = (ch == 'a');
  429. X
  430. X                n = search_author(show_only_unread, (int) base[index_point], i);
  431. X                if (n < 0)
  432. X                    break;
  433. X
  434. X                index_point = show_page (n, &dummy, group, group_path);
  435. X                if (index_point < 0) {
  436. X                    space_mode = FALSE;
  437. X                    goto group_done;
  438. X                }
  439. X                clear_note_area ();
  440. X                show_group_page (group);
  441. X                break;
  442. X
  443. X            case 'B':    /* bug/gripe/comment mailed to author */
  444. X                mail_bug_report ();
  445. X#ifndef USE_CLEARSCREEN
  446. X                ClearScreen ();
  447. X#endif
  448. X                show_group_page (group);
  449. X                break;
  450. X                
  451. X            case 'c':    /* catchup - mark all articles as read */
  452. X                if (!confirm_action || prompt_yn (LINES, txt_mark_all_read, 'y')) {
  453. X                    for (n = 0; n < top; n++) {
  454. X                        arts[n].unread = ART_READ;
  455. X                    }
  456. X                    if (cur_groupnum + 1 < group_top) {
  457. X                        cur_groupnum++;
  458. X                    }
  459. X                    goto group_done;
  460. X                }
  461. X                break;
  462. X
  463. X            case 'd':    /* toggle display of subject & subj/author */
  464. X                toggle_subject_from ();
  465. X                show_group_page (group);
  466. X                break;
  467. X
  468. X            case 'g':    /* choose a new group by name */
  469. X                n = choose_new_group ();
  470. X                if (n >= 0 && n != cur_groupnum) {
  471. X                    cur_groupnum = n;
  472. X                    index_point = -3;
  473. X                    goto group_done;
  474. X                }
  475. X                break;
  476. X
  477. X            case 'h':    /* help */
  478. X                show_info_page (HELP_INFO, help_group, txt_index_page_com);
  479. X                show_group_page (group);
  480. X                break;
  481. X
  482. X            case 'I':    /* toggle inverse video */
  483. X                toggle_inverse_video ();
  484. X                show_group_page (group);
  485. X                break;
  486. X
  487. X            case 'K':    /* mark rest of thread as read */
  488. X                if (index_point < 0) {
  489. X                    info_message (txt_no_next_unread_art);
  490. X                    break;
  491. X                }
  492. X                if (new_responses (index_point)) {
  493. X                    n = (int) base[index_point];
  494. X                    for (i = (int) base[index_point]; i >= 0; i = arts[i].thread) {
  495. X                        arts[i].unread = ART_READ;
  496. X                    }    
  497. X                    if (arts[n].tagged) {
  498. X                        sprintf (msg, "%3d", arts[n].tagged);
  499. X                    } else {
  500. X                        sprintf (msg, "   ");
  501. X                    }
  502. X                    if (show_only_unread) {
  503. X                        strcat (msg, "   ");
  504. X                    }                    
  505. X                    mark_screen (GROUP_LEVEL, index_point - first_subj_on_screen,
  506. X                        SCREEN_READ_UNREAD, msg);    
  507. X                    flag = FALSE;
  508. X                } else {
  509. X                    flag = TRUE;
  510. X                }
  511. X                n = next_unread (next_response ((int) base[index_point]));
  512. X                if (n < 0) {
  513. X                    if (flag)
  514. X                        info_message (txt_no_next_unread_art);
  515. X                    else
  516. X                        MoveCursor (LINES, 0);
  517. X                    break;
  518. X                }
  519. X
  520. X                if ((n = which_thread (n)) < 0) {
  521. X                    error_message("Internal error: K which_thread < 0", "");
  522. X                    break;
  523. X                }
  524. X
  525. X                if (n >= last_subj_on_screen) {
  526. X                    index_point = n;
  527. X                    show_group_page (group);
  528. X                } else {
  529. X                    erase_subject_arrow ();
  530. X                    index_point = n;
  531. X                    draw_subject_arrow ();
  532. X                }
  533. X                break;
  534. X
  535. X            case 'l':    /* list articles within current thread */
  536. X                if (index_point < 0) {
  537. X                    info_message (txt_no_arts);
  538. X                    break;
  539. X                }
  540. X                 space_mode = TRUE;
  541. X                n = show_thread ((int) base[index_point], group, group_path);
  542. X                if (n == -2) {
  543. X                    index_point = n;
  544. X                    space_mode = FALSE;
  545. X                    goto group_done;
  546. X                } else {
  547. X                    if (index_point < 0) {
  548. X                        space_mode = FALSE;
  549. X                        goto group_done;
  550. X                    }
  551. X                    clear_note_area ();
  552. X                    show_group_page (group);
  553. X                }
  554. X                break;    
  555. X
  556. X            case 'm':    /* mail article to somebody */
  557. X                if (index_point >= 0) {
  558. X                    feed_articles (FEED_MAIL, GROUP_LEVEL, "Mail",
  559. X                        (int) base[index_point], group_path);
  560. X                }
  561. X                break;
  562. X
  563. X            case 'M':    /* options menu */
  564. X                if (top_base > 0) {
  565. X                    old_top = top;
  566. X                    n = (int) base[index_point];
  567. X                    old_artnum = arts[n].artnum;
  568. X                }
  569. X                n = sort_art_type;
  570. X                kill_state = change_rcfile (group, TRUE);
  571. X                if (kill_state == NO_KILLING && n != sort_art_type) {
  572. X                    make_threads (TRUE);
  573. X                    find_base (show_only_unread);
  574. X                }
  575. X                index_point = find_new_pos (old_top, old_artnum, index_point);
  576. X                show_group_page (group);
  577. X                break;
  578. X
  579. X            case 'n':    /* next group */
  580. X                clear_message();
  581. X                if (cur_groupnum + 1 >= group_top)
  582. X                    info_message(txt_no_more_groups);
  583. X                else {
  584. X                    cur_groupnum++;
  585. X                    index_point = -3;
  586. X                    space_mode = pos_first_unread;
  587. X                    goto group_done;
  588. X                }
  589. X                break;
  590. X
  591. X            case 'N':    /* go to next unread article */
  592. X                if (index_point < 0) {
  593. X                    info_message(txt_no_next_unread_art);
  594. X                    break;
  595. X                }
  596. X
  597. X                n = next_unread ((int) base[index_point]);
  598. X                if (n == -1)
  599. X                    info_message (txt_no_next_unread_art);
  600. X                else {
  601. X                    index_point = show_page (n, &dummy, group, group_path);
  602. X                    if (index_point < 0) {
  603. X                        space_mode = pos_first_unread;
  604. X                        goto group_done;
  605. X                    }
  606. X                    clear_note_area ();
  607. X                    show_group_page (group);
  608. X                }
  609. X                break;
  610. X
  611. X            case 'o':    /* output art/thread/tagged arts to printer */
  612. X                if (index_point >= 0) {
  613. X                    feed_articles (FEED_PRINT, GROUP_LEVEL, "Print",
  614. X                        (int) base[index_point], group_path);
  615. X                }
  616. X                break;
  617. X
  618. X            case 'p':    /* previous group */
  619. X                clear_message();
  620. X                if (cur_groupnum <= 0)
  621. X                    info_message(txt_no_prev_group);
  622. X                else {
  623. X                    cur_groupnum--;
  624. X                    index_point = -3;
  625. X                    space_mode = pos_first_unread;
  626. X                    goto group_done;
  627. X                }
  628. X                break;
  629. X
  630. X            case 'P':    /* go to previous unread article */
  631. X                if (index_point < 0) {
  632. X                    info_message(txt_no_prev_unread_art);
  633. X                    break;
  634. X                }
  635. X                n = prev_response ((int) base[index_point]);
  636. X                n = prev_unread (n);
  637. X                if (n == -1)
  638. X                    info_message(txt_no_prev_unread_art);
  639. X                else {
  640. X                    index_point = show_page (n, &dummy, group, group_path);
  641. X                    if (index_point < 0) {
  642. X                        space_mode = pos_first_unread;
  643. X                        goto group_done;
  644. X                    }
  645. X                    clear_note_area ();
  646. X                    show_group_page (group);
  647. X                }
  648. X                break;
  649. X
  650. X            case 'q':    /* return to group selection page */
  651. X                goto group_done;
  652. X
  653. X            case 'Q':        /* quit */
  654. X                index_point = -2;
  655. X                space_mode = FALSE;
  656. X                goto group_done;
  657. X
  658. X             case 'r':        
  659. X                 /* If in show_only_unread mode or there are unread 
  660. X                articles we know this thread will exist after 
  661. X                toggle. Otherwise we find the next closest */
  662. X                 i = -1;
  663. X                 if (index_point >= 0) {
  664. X                     if (show_only_unread || new_responses(index_point))
  665. X                         i = base[index_point];
  666. X                     else if ((n = prev_unread(base[index_point])) >= 0)
  667. X                         i = n;
  668. X                     else if ((n = next_unread(base[index_point])) >= 0)
  669. X                         i = n;
  670. X                 }
  671. X                 show_only_unread = (show_only_unread ? FALSE : TRUE);
  672. X                 make_threads (TRUE);
  673. X                 find_base (show_only_unread);
  674. X                 if (i >= 0 && (n = which_thread(i)) >= 0)
  675. X                     index_point = n;
  676. X                 else if (top_base > 0)
  677. X                     index_point = top_base - 1;
  678. X                 show_group_page (group);
  679. X                 break;
  680. X
  681. X            case 's':    /* save regex pattern to file/s */
  682. X                if (index_point >= 0) {
  683. X                    feed_articles (FEED_SAVE, GROUP_LEVEL, "Save",
  684. X                        (int) base[index_point], group_path);
  685. X                }
  686. X                break;
  687. X            
  688. X            case 'T':    /* tag/untag art for mailing/piping/printing/saving */
  689. X                 if (index_point >= 0) {
  690. X                    n = (int) base[index_point];
  691. X                    if (arts[n].tagged) {
  692. X                        arts[n].tagged = 0;
  693. X                        sprintf (msg, "%3s", (arts[n].unread ? "  +" : "   "));
  694. X                        info_message (txt_untagged_art);
  695. X                    } else {
  696. X                        arts[n].tagged = ++num_of_tagged_arts;
  697. X                        sprintf (msg, "%3d", arts[n].tagged);
  698. X                        info_message (txt_tagged_art);
  699. X                    }
  700. X                    mark_screen (GROUP_LEVEL, index_point - first_subj_on_screen,
  701. X                        SCREEN_READ_UNREAD, msg);
  702. X                    goto group_down;    /* advance an article */
  703. X                }
  704. X                break;
  705. X
  706. X            case 'u':    /* unthread/thread articles */
  707. X                 if (index_point >= 0) {
  708. X                    thread_arts = !thread_arts;
  709. X                    make_threads (TRUE);
  710. X                    find_base (show_only_unread);
  711. X                    show_group_page (group);
  712. X                }
  713. X                break;
  714. X
  715. X            case 'U':    /* untag all articles */
  716. X                 if (index_point >= 0) {
  717. X                    untag_all_articles ();
  718. X                    show_group_page (group);
  719. X                }
  720. X                break;
  721. X
  722. X            case 'v':
  723. X                info_message (cvers);
  724. X                break;
  725. X
  726. X            case 'w':    /* post a basenote */
  727. X                if (! can_post) {
  728. X                    info_message (txt_cannot_post);
  729. X                    break;
  730. X                }
  731. X                if (post_base (group, &posted)) {
  732. X                    show_group_page (group);
  733. X                }
  734. X                break;
  735. X
  736. X            case 'W':    /* display messages posted by user */
  737. X                if (user_posted_messages ()) {
  738. X                    show_group_page (group);
  739. X                }
  740. X                break;
  741. X
  742. X            case 'x':    /* crosspost current article */
  743. X                if (index_point >= 0) {
  744. X                    feed_articles (FEED_XPOST, GROUP_LEVEL, "Crosspost",
  745. X                        (int) base[index_point], group_path);
  746. X                }
  747. X                break;
  748. X
  749. X            case 'z':    /* mark article as unread */
  750. X            case 'Z':    /* mark thread as unread */
  751. X                 if (index_point < 0) {
  752. X                     info_message (txt_no_arts);
  753. X                    break;
  754. X                }
  755. X                n = 0;
  756. X                for (i = (int) base[index_point] ; i != -1 ; i = arts[i].thread) {
  757. X                    arts[i].unread = ART_UNREAD;
  758. X                    ++n;
  759. X                    if (ch == 'z')
  760. X                        break;
  761. X                }
  762. X                assert (n > 0);
  763. X                stat_thread (index_point, &sbuf); /* for art_mark */
  764. X                if (show_only_unread) {
  765. X                    n = ART_ADJUST(sbuf.unread+sbuf.seen);
  766. X                } else {
  767. X                    n = ART_ADJUST(sbuf.total);
  768. X                }    
  769. X                if (n > 0) {
  770. X                    sprintf (buf, "  %c %d", sbuf.art_mark, n);
  771. X                } else {
  772. X                    sprintf (buf, "  %c   ", sbuf.art_mark);
  773. X                }    
  774. X                mark_screen (GROUP_LEVEL, index_point - first_subj_on_screen,
  775. X                    SCREEN_READ_UNREAD, buf);    
  776. X                info_message (txt_thread_marked_as_unread);
  777. X                break;
  778. X
  779. X            default:
  780. X                info_message (txt_bad_command);
  781. X        }
  782. X    }
  783. X
  784. Xgroup_done:
  785. X    fix_new_highest (sav_groupnum);
  786. X    update_newsrc (group, my_group[sav_groupnum], FALSE);
  787. X
  788. X    if (index_point == -2) {
  789. X        write_rcfile ();
  790. X        tin_done (0);
  791. X    }    
  792. X    clear_note_area ();
  793. X
  794. X#endif /* INDEX_DAEMON */
  795. X}
  796. X
  797. X
  798. X/*
  799. X *  Correct highest[] for the group selection page display since
  800. X *  new articles may have been read or marked unread
  801. X */
  802. X
  803. Xvoid fix_new_highest (groupnum)
  804. X    int groupnum;
  805. X{
  806. X    register int i;
  807. X    int sum = 0;
  808. X
  809. X    for (i = 0; i < top; i++) {
  810. X        if (arts[i].unread) {
  811. X            sum++;
  812. X        }
  813. X    }
  814. X    
  815. X    unread[groupnum] = sum;
  816. X}
  817. X
  818. X
  819. Xvoid show_group_page (group)
  820. X    char *group;
  821. X{
  822. X#ifndef INDEX_DAEMON
  823. X
  824. X    char buf[LEN];
  825. X    char new_resps[8];
  826. X    char resps[8];
  827. X    char from[LEN];
  828. X    char *spaces;
  829. X    int i, j, n;
  830. X    int len_from;
  831. X    int len_subj;
  832. X    int respnum;
  833. X    int art_cnt = 0;
  834. X    struct art_stat_t sbuf;
  835. X
  836. X    set_signals_group ();
  837. X    
  838. X#ifdef USE_CLEARSCREEN
  839. X    ClearScreen ();
  840. X#else
  841. X    MoveCursor (0, 0);
  842. X    CleartoEOLN ();
  843. X#endif
  844. X
  845. X    if (show_only_unread) {
  846. X        for (i = 0 ; i < top_base ; i++) {
  847. X            art_cnt += new_responses (i);
  848. X        }    
  849. X    } else {
  850. X        for (i = 0 ; i < top ; i++) {
  851. X            if (! IGNORE_ART(i)) {
  852. X                ++art_cnt;
  853. X            }
  854. X        }        
  855. X    }
  856. X
  857. X    if (active[my_group[cur_groupnum]].attribute.thread && thread_arts) {
  858. X        sprintf (buf, "%s (%dT %dA %dK %dH)", group, top_base, art_cnt,
  859. X            num_of_killed_arts, num_of_hot_arts);
  860. X    } else {
  861. X        sprintf (buf, "%s (%dU %dK %dH)", group, art_cnt, 
  862. X            num_of_killed_arts, num_of_hot_arts);
  863. X    }
  864. X    show_title (buf);
  865. X
  866. X#ifndef USE_CLEARSCREEN
  867. X    MoveCursor (1, 0);
  868. X    CleartoEOLN ();
  869. X#endif
  870. X
  871. X    MoveCursor (INDEX_TOP, 0);
  872. X
  873. X    if (index_point >= top_base) {
  874. X        index_point = top_base - 1;
  875. X    }
  876. X
  877. X    if (NOTESLINES <= 0) {
  878. X        first_subj_on_screen = 0;
  879. X    } else {
  880. X        first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES;
  881. X        if (first_subj_on_screen < 0) {
  882. X            first_subj_on_screen = 0;
  883. X        }
  884. X    }
  885. X
  886. X    last_subj_on_screen = first_subj_on_screen + NOTESLINES;
  887. X
  888. X    if (last_subj_on_screen >= top_base) {
  889. X        last_subj_on_screen = top_base;
  890. X        first_subj_on_screen = (top_base / NOTESLINES) * NOTESLINES;
  891. X
  892. X        if (first_subj_on_screen == last_subj_on_screen ||
  893. X            first_subj_on_screen < 0) {
  894. X            if (first_subj_on_screen < 0) {
  895. X                first_subj_on_screen = 0;
  896. X            } else {
  897. X                first_subj_on_screen = last_subj_on_screen - NOTESLINES;
  898. X            }
  899. X        }
  900. X    }
  901. X
  902. X    if (top_base == 0) {
  903. X        first_subj_on_screen = 0;
  904. X        last_subj_on_screen = 0;
  905. X    }
  906. X
  907. X    if (draw_arrow_mark) {
  908. X        CleartoEOS ();
  909. X    }
  910. X
  911. X    if (show_author != SHOW_FROM_NONE) {
  912. X        len_from = max_from - BLANK_GROUP_COLS;
  913. X        len_subj = max_subj;
  914. X        spaces = "   ";
  915. X    } else {
  916. X        from[0] = '\0';
  917. X        len_from = 0;
  918. X        len_subj = (max_subj+max_from+3) - BLANK_GROUP_COLS;
  919. X        spaces = "";
  920. X    }
  921. X
  922. X    for (j=0, i = first_subj_on_screen; i < last_subj_on_screen; i++, j++) {
  923. X        respnum = (int) base[i];
  924. X
  925. X        stat_thread(i, &sbuf);
  926. X        if (show_only_unread)
  927. X            n = sbuf.unread + sbuf.seen;
  928. X        else
  929. X            n = sbuf.total;
  930. X
  931. X        n = ART_ADJUST(n);
  932. X
  933. X        if (arts[respnum].tagged) {
  934. X            sprintf (new_resps, "%3d", arts[respnum].tagged);
  935. X        } else {
  936. X            sprintf (new_resps, "  %c", sbuf.art_mark);
  937. X        }
  938. X
  939. X        if (n) {
  940. X            sprintf (resps, "%-3d", n); 
  941. X        } else {
  942. X            strcpy (resps, "   ");
  943. X        }
  944. X
  945. X        if (show_author != SHOW_FROM_NONE) {
  946. X            get_author (FALSE, respnum, from);
  947. X        }    
  948. X
  949. X        sprintf (screen[j].col, "  %4d%3s %s%-*.*s%s%-*.*s\r\n",
  950. X             i+1, new_resps, resps, len_subj, len_subj, 
  951. X             arts[respnum].subject, spaces, len_from, len_from, from);
  952. X
  953. X        fputs (screen[j].col, stdout);
  954. X    }
  955. X
  956. X#ifndef USE_CLEARSCREEN
  957. X    CleartoEOS ();
  958. X#endif
  959. X
  960. X    if (top_base <= 0) {
  961. X        info_message(txt_no_arts);
  962. X        return;
  963. X    } else if (last_subj_on_screen == top_base) {
  964. X        info_message(txt_end_of_arts);
  965. X    }
  966. X
  967. X    draw_subject_arrow();
  968. X
  969. X#endif /* INDEX_DAEMON */
  970. X}
  971. X
  972. X
  973. Xvoid draw_subject_arrow()
  974. X{
  975. X    draw_arrow (INDEX_TOP + (index_point-first_subj_on_screen));
  976. X}
  977. X
  978. Xvoid erase_subject_arrow()
  979. X{
  980. X    erase_arrow (INDEX_TOP + (index_point-first_subj_on_screen));
  981. X}
  982. X
  983. X
  984. Xvoid prompt_subject_num (ch, group)
  985. X    char ch;
  986. X    char *group;
  987. X{
  988. X    int num;
  989. X
  990. X    if (! top_base) {
  991. X        return;
  992. X    }
  993. X
  994. X    clear_message ();
  995. X
  996. X    if ((num = prompt_num (ch, txt_read_art)) == -1) {
  997. X        clear_message ();
  998. X        return;
  999. X    }
  1000. X    num--;        /* index from 0 (internal) vs. 1 (user) */
  1001. X
  1002. X    if (num < 0) {
  1003. X        num = 0;
  1004. X    }
  1005. X    if (num >= top_base) {
  1006. X        num = top_base - 1;
  1007. X    }
  1008. X
  1009. X    if (num >= first_subj_on_screen
  1010. X    &&  num < last_subj_on_screen) {
  1011. X        erase_subject_arrow();
  1012. X        index_point = num;
  1013. X        draw_subject_arrow();
  1014. X    } else {
  1015. X#ifndef USE_CLEARSCREEN
  1016. X        erase_subject_arrow();
  1017. X#endif        
  1018. X        index_point = num;
  1019. X        show_group_page(group);
  1020. X    }
  1021. X}
  1022. X
  1023. X
  1024. Xvoid clear_note_area ()
  1025. X{
  1026. X#ifndef USE_CLEARSCREEN
  1027. X    MoveCursor (INDEX_TOP, 0);
  1028. X    CleartoEOS ();
  1029. X#endif
  1030. X}
  1031. X
  1032. X/*
  1033. X * Find new index position after a kill or unkill. Because
  1034. X * kill can work on author it is impossible to know which,
  1035. X * if any, articles will be left afterwards. So we make a
  1036. X * "best attempt" to find a new index point.
  1037. X */
  1038. X
  1039. Xint find_new_pos (old_top, old_artnum, cur_pos)
  1040. X    int old_top;
  1041. X    long old_artnum;
  1042. X    int cur_pos;
  1043. X{
  1044. X    int pos;
  1045. X    
  1046. X     if (top == old_top) {
  1047. X         return (cur_pos);
  1048. X     }    
  1049. X  
  1050. X     if ((pos = valid_artnum (old_artnum)) >= 0) {
  1051. X         if ((pos = which_thread (pos)) >= 0){
  1052. X             return pos;
  1053. X         }
  1054. X     }        
  1055. X     
  1056. X     if (cur_pos < top_base) {
  1057. X         return cur_pos;
  1058. X     } else {
  1059. X         return (top_base - 1);
  1060. X     }    
  1061. X}
  1062. X
  1063. X
  1064. Xvoid mark_screen (level, screen_row, screen_col, value)
  1065. X    int level;
  1066. X    int screen_row;
  1067. X    int screen_col;
  1068. X    char *value;
  1069. X{
  1070. X    int i, len;
  1071. X
  1072. X    len = strlen (value);
  1073. X    
  1074. X    if (draw_arrow_mark) {
  1075. X        MoveCursor(INDEX_TOP + screen_row, screen_col);
  1076. X        fputs (value, stdout);
  1077. X        MoveCursor (LINES, 0);
  1078. X        fflush (stdout);
  1079. X    } else {
  1080. X        for (i=0 ; i < len ; i++) {
  1081. X            screen[screen_row].col[screen_col+i] = value[i];
  1082. X        }
  1083. X        if (level == SELECT_LEVEL) {
  1084. X            draw_group_arrow();
  1085. X        } else {
  1086. X            draw_subject_arrow();
  1087. X        }    
  1088. X    }
  1089. X}
  1090. X
  1091. X
  1092. Xvoid set_subj_from_size (num_cols)
  1093. X    int num_cols;
  1094. X{
  1095. X    int size = 0;
  1096. X    
  1097. X    if (show_author == SHOW_FROM_BOTH) {
  1098. X        max_subj = (num_cols / 2) - 2;
  1099. X    } else {
  1100. X        max_subj = (num_cols / 2) + 5;
  1101. X    }
  1102. X    max_from = (num_cols - max_subj) - 17;
  1103. X
  1104. X    if (show_author != SHOW_FROM_BOTH) {
  1105. X        if (max_from > 25) {
  1106. X            size = max_from - 25;
  1107. X            max_from = 25;
  1108. X            max_subj = max_subj + size;
  1109. X        }
  1110. X    }
  1111. X}
  1112. X
  1113. X
  1114. Xvoid toggle_subject_from ()
  1115. X{
  1116. X    if (default_show_author != SHOW_FROM_NONE) {
  1117. X        if (show_author != SHOW_FROM_NONE) {
  1118. X            show_author = SHOW_FROM_NONE;
  1119. X        } else {
  1120. X            show_author = default_show_author;
  1121. X        }
  1122. X    } else {
  1123. X        if (show_author + 1 > SHOW_FROM_BOTH) {
  1124. X            show_author = SHOW_FROM_NONE;
  1125. X        } else {
  1126. X            show_author++;
  1127. X        }
  1128. X    }
  1129. X    set_subj_from_size (COLS);
  1130. X}
  1131. END_OF_FILE
  1132.   if test 24125 -ne `wc -c <'group.c'`; then
  1133.     echo shar: \"'group.c'\" unpacked with wrong size!
  1134.   fi
  1135.   # end of 'group.c'
  1136. fi
  1137. if test -f 'post.c' -a "${1}" != "-c" ; then 
  1138.   echo shar: Will not clobber existing file \"'post.c'\"
  1139. else
  1140.   echo shar: Extracting \"'post.c'\" \(26765 characters\)
  1141.   sed "s/^X//" >'post.c' <<'END_OF_FILE'
  1142. X/*
  1143. X *  Project   : tin - a threaded Netnews reader
  1144. X *  Module    : post.c
  1145. X *  Author    : I.Lea
  1146. X *  Created   : 01-04-91
  1147. X *  Updated   : 11-05-92
  1148. X *  Notes     : mail/post/replyto/followup/crosspost & cancel articles
  1149. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  1150. X *              You may  freely  copy or  redistribute  this software,
  1151. X *              so  long as there is no profit made from its use, sale
  1152. X *              trade or  reproduction.  You may not change this copy-
  1153. X *              right notice, and it must be included in any copy made
  1154. X */
  1155. X
  1156. X#include    "tin.h"
  1157. X
  1158. Xextern char note_h_distrib[LEN];        /* Distribution: */
  1159. Xextern char note_h_followup[LEN];        /* Followup-To: */
  1160. Xextern char note_h_messageid[LEN];        /* Message-ID:    */
  1161. Xextern char note_h_newsgroups[LEN];        /* Newsgroups:    */
  1162. Xextern char note_h_subj[LEN];            /* Subject:    */
  1163. Xextern char note_h_date[LEN];            /* Date:    */
  1164. Xextern FILE *note_fp;                /* the body of the current article */
  1165. Xextern int cur_groupnum;
  1166. Xextern long note_mark[MAX_PAGES];        /* ftells on beginnings of pages */
  1167. X
  1168. Xchar default_post_subject[LEN];    
  1169. X
  1170. Xint unlink_article = TRUE;
  1171. Xstruct posted_t *posted;
  1172. X
  1173. X
  1174. Xint user_posted_messages ()
  1175. X{
  1176. X    char buf[LEN];
  1177. X    FILE *fp;
  1178. X    int i, j, k;
  1179. X    int no_of_lines = 0;
  1180. X
  1181. X    if ((fp = fopen (postfile, "r")) == NULL) {
  1182. X        clear_message ();
  1183. X        return FALSE;
  1184. X    } else {
  1185. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1186. X            no_of_lines++;
  1187. X        }
  1188. X        if (! no_of_lines) {
  1189. X            fclose (fp);
  1190. X            info_message (txt_no_arts_posted);
  1191. X            return FALSE;
  1192. X        }
  1193. X        rewind (fp);
  1194. X        posted = (struct posted_t *) my_malloc ((unsigned) (no_of_lines+1) * sizeof (struct posted_t));
  1195. X        for (i=0 ; fgets (buf, sizeof (buf), fp) != NULL ; i++) {
  1196. X            for (j=0 ; buf[j] != '|' && buf[j] != '\n' ; j++) {
  1197. X                posted[i].date[j] = buf[j];        /* posted date */
  1198. X            }
  1199. X            if (buf[j] == '\n') {    
  1200. X                error_message ("Corrupted file %s", postfile);
  1201. X                sleep (1);
  1202. X                fclose (fp);
  1203. X                clear_message ();
  1204. X                return FALSE;
  1205. X            }
  1206. X            posted[i].date[j++] = '\0';
  1207. X            posted[i].action = buf[j];
  1208. X            j += 2;
  1209. X            for (k=j,j=0 ; buf[k] != '|' && buf[k] != ',' ; k++, j++) {
  1210. X                posted[i].group[j] = buf[k];
  1211. X            }
  1212. X            if (buf[k] == ',') {
  1213. X                while (buf[k] != '|' && buf[k] != '\n') {
  1214. X                    k++;
  1215. X                }
  1216. X                posted[i].group[j++] = ',';
  1217. X                posted[i].group[j++] = '.';
  1218. X                posted[i].group[j++] = '.';
  1219. X                posted[i].group[j++] = '.';
  1220. X            }
  1221. X            posted[i].group[j++] = '\0';
  1222. X            k++;
  1223. X            for (j=k,k=0 ; buf[j] != '\n' ; j++, k++) {
  1224. X                posted[i].subj[k] = buf[j];
  1225. X            }
  1226. X            posted[i].subj[k++] = '\0';
  1227. X        }
  1228. X        fclose (fp);
  1229. X
  1230. X        show_info_page (POST_INFO, (char **) 0, txt_post_history_menu);
  1231. X        if (posted != (struct posted_t *) 0) {
  1232. X            free ((char *) posted);
  1233. X            posted = (struct posted_t *) 0;
  1234. X        }
  1235. X        return TRUE;
  1236. X    }
  1237. X}
  1238. X
  1239. X
  1240. Xvoid update_art_posted_file (group, action, subj)
  1241. X    char *group;
  1242. X    int action;
  1243. X    char *subj;
  1244. X{
  1245. X    char buf[LEN];
  1246. X    char tmp_post[LEN];
  1247. X    FILE *fp, *tmp_fp;
  1248. X    long epoch;
  1249. X    struct tm *tm;
  1250. X
  1251. X    sprintf (tmp_post, "%s.%d", postfile, process_id);
  1252. X
  1253. X    if ((tmp_fp = fopen (tmp_post, "w")) != NULL) {
  1254. X        time (&epoch);
  1255. X        tm = localtime (&epoch);
  1256. X        fprintf (tmp_fp, "%02d-%02d-%02d|%c|%s|%s\n",
  1257. X            tm->tm_mday, tm->tm_mon+1, tm->tm_year,
  1258. X            action, group, subj);
  1259. X        fclose (tmp_fp);
  1260. X    }
  1261. X
  1262. X    if ((tmp_fp = fopen (tmp_post, "a+")) != NULL) {
  1263. X        if ((fp = fopen (postfile, "r")) != NULL) {
  1264. X            while (fgets (buf, sizeof buf, fp) != NULL) {
  1265. X                fprintf (tmp_fp, "%s", buf);
  1266. X            }    
  1267. X            fclose (fp);
  1268. X            rename_file (tmp_post, postfile);
  1269. X        }
  1270. X        fclose (tmp_fp);
  1271. X    }
  1272. X}
  1273. X
  1274. X/*
  1275. X * Check the article file so that it is not missing the blank line
  1276. X * between the header information and the text.
  1277. X */
  1278. X
  1279. Xint post_header_ok (article)
  1280. X    char* article;
  1281. X{
  1282. X    FILE *fp;
  1283. X    char line[LEN];
  1284. X    int cnt= 0;
  1285. X    int len, ind;
  1286. X    char prev_ch;
  1287. X    int header;
  1288. X
  1289. X    if ((fp = fopen (article, "r")) == NULL) {
  1290. X        perror_message (txt_cannot_open, article);
  1291. X        return FALSE;
  1292. X    }
  1293. X
  1294. X    while (fgets (line, sizeof (line), fp) != NULL) {
  1295. X        cnt++;
  1296. X        len= strlen (line);
  1297. X        if (len > 0)
  1298. X            if (line[len - 1] == '\n') 
  1299. X                line[--len]= 0;
  1300. X                
  1301. X        if ((len == 0) && (cnt >= 2)) {
  1302. X            fclose(fp);
  1303. X            return TRUE;
  1304. X        }
  1305. X        prev_ch= ' ';
  1306. X        header= FALSE;
  1307. X        for (ind= 0; ind < len; ind++) /* Skip white space */
  1308. X            if ((line[ind] != ' ') && (line[ind] != '\t'))
  1309. X                break;
  1310. X        for (; ind < len; ind++) {   
  1311. X            /* Header as long as the first token ends with ':' */
  1312. X            if (((ind == len - 1) &&
  1313. X                 (line[ind] == ':')) ||
  1314. X                (((line[ind] == ' ') ||
  1315. X                  (line[ind] == '\t')) &&
  1316. X                 (prev_ch == ':'))) {
  1317. X                header= TRUE;
  1318. X                break;
  1319. X            }
  1320. X
  1321. X            if ((line[ind] == ' ') ||
  1322. X                (line[ind] == '\t'))
  1323. X                break;
  1324. X            prev_ch= line[ind];
  1325. X        }
  1326. X        if (! header) {
  1327. X            fclose (fp);
  1328. X            return FALSE;
  1329. X        }
  1330. X    }
  1331. X    fclose (fp);
  1332. X    return FALSE;
  1333. X}
  1334. X
  1335. X/*
  1336. X *  Post an original article (not a followup)
  1337. X */
  1338. X
  1339. Xint post_base (group, posted)
  1340. X    char *group;
  1341. X    int *posted;
  1342. X{
  1343. X    FILE *fp;
  1344. X    char ch;
  1345. X    char ch_default = 'p';
  1346. X    char subj[LEN];
  1347. X    char buf[LEN];
  1348. X    int redraw_screen = FALSE;
  1349. X
  1350. X    /*
  1351. X     * Don't allow if not active news feed 
  1352. X     */
  1353. X    if (! spooldir_is_active) {
  1354. X        info_message (txt_not_active_newsfeed);
  1355. X        return (redraw_screen);
  1356. X    }
  1357. X    
  1358. X    *posted = FALSE;
  1359. X    start_line_offset = 7;
  1360. X
  1361. X    if (active[my_group[cur_groupnum]].moderated == 'm') {
  1362. X        sprintf (msg, "Group %s is moderated. Continue? (y/n): ", group);
  1363. X        if (! prompt_yn (LINES, msg, 'y')) {
  1364. X            clear_message ();
  1365. X            return (redraw_screen);
  1366. X        }
  1367. X    }
  1368. X
  1369. X    sprintf (msg, txt_post_subject, default_post_subject);
  1370. X    
  1371. X    if (! prompt_string (msg, subj)) {
  1372. X        clear_message ();
  1373. X        return (redraw_screen);
  1374. X    }
  1375. X
  1376. X    if (strlen (subj)) {
  1377. X        my_strncpy (default_post_subject, subj,
  1378. X            sizeof (default_post_subject));
  1379. X    } else {
  1380. X        if (default_post_subject[0]) {
  1381. X            my_strncpy (subj, default_post_subject, sizeof (subj));
  1382. X        } else {
  1383. X            info_message (txt_no_subject);
  1384. X            return (redraw_screen);
  1385. X        }
  1386. X    }
  1387. X    
  1388. X    wait_message (txt_post_an_article);
  1389. X
  1390. X    if ((fp = fopen (article, "w")) == NULL) {
  1391. X        perror_message (txt_cannot_open, article);
  1392. X        return (redraw_screen);
  1393. X    }
  1394. X    chmod (article, 0600);
  1395. X
  1396. X    fprintf (fp, "Subject: %s\n", subj);
  1397. X    fprintf (fp, "Newsgroups: %s\n", group);
  1398. X    if (*my_org) {
  1399. X        fprintf (fp, "Organization: %s\n", my_org);
  1400. X        start_line_offset++;
  1401. X    }
  1402. X    if (*reply_to) {
  1403. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1404. X        start_line_offset++;
  1405. X    }
  1406. X    fprintf (fp, "Distribution: %s\n", my_distribution);
  1407. X    fprintf (fp, "Summary: \n");
  1408. X    fprintf (fp, "Keywords: \n\n");
  1409. X
  1410. X    add_signature (fp, FALSE);
  1411. X    fclose (fp);
  1412. X
  1413. X    ch = 'e';
  1414. X    while (1) {
  1415. X        switch (ch) {
  1416. X        case 'e':
  1417. X            invoke_editor (article);
  1418. X            while (! post_header_ok(article)) {
  1419. X                do {
  1420. X                    sprintf (msg, "%s%c", txt_no_blank_line, 'e');
  1421. X                    wait_message (msg);
  1422. X                    MoveCursor (LINES, (int) strlen (txt_no_blank_line));
  1423. X                    if ((ch = (char) ReadCh ()) == CR)
  1424. X                        ch = 'e';
  1425. X                } while (ch != ESC && ch != 'q' && ch != 'e');
  1426. X                if (ch == 'e')
  1427. X                    invoke_editor (article);
  1428. X                else
  1429. X                    break;
  1430. X            }
  1431. X            redraw_screen = TRUE;
  1432. X            if (ch == 'e') {
  1433. X                break;
  1434. X            }
  1435. X        case 'q':
  1436. X        case ESC:
  1437. X            if (unlink_article)
  1438. X                unlink (article);
  1439. X            clear_message ();
  1440. X            return (redraw_screen);
  1441. X
  1442. X        case 'p':
  1443. X            wait_message (txt_posting);
  1444. X            if (submit_file (article)) {
  1445. X                info_message (txt_art_posted);
  1446. X                *posted = TRUE;
  1447. X                goto post_base_done;
  1448. X            } else {
  1449. X                rename_file (article, dead_article);
  1450. X                sprintf (buf, txt_art_rejected, dead_article);
  1451. X                info_message (buf);
  1452. X                sleep (3);
  1453. X                return (redraw_screen);
  1454. X            }
  1455. X        }
  1456. X
  1457. X        do {
  1458. X            sprintf (msg, "%s%c", txt_quit_edit_post, ch_default);
  1459. X            wait_message (msg);
  1460. X            MoveCursor (LINES, (int) strlen (txt_quit_edit_post));
  1461. X            if ((ch = (char) ReadCh ()) == CR)
  1462. X                ch = ch_default;
  1463. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 'p');
  1464. X    }
  1465. X
  1466. Xpost_base_done:
  1467. X    find_mail_header (HEADER_SUBJECT, article, subj);
  1468. X    if (unlink_article)
  1469. X        unlink (article);
  1470. X    update_art_posted_file (group, 'w', subj);
  1471. X    /*
  1472. X     * Update default posting prompt
  1473. X     */
  1474. X    my_strncpy (default_post_subject, subj, sizeof (default_post_subject));
  1475. X
  1476. X    return (redraw_screen);
  1477. X}
  1478. X
  1479. X
  1480. Xint post_response (group, respnum, copy_text)
  1481. X    char *group;
  1482. X    int respnum;
  1483. X    int copy_text;
  1484. X{
  1485. X    FILE *fp;
  1486. X    char ch, *ptr;
  1487. X    char ch_default = 'p';
  1488. X    char buf[LEN];
  1489. X    int ret_code = POSTED_NONE;
  1490. X    
  1491. X    /*
  1492. X     * Don't allow if not active news feed 
  1493. X     */
  1494. X    if (! spooldir_is_active) {
  1495. X        info_message (txt_not_active_newsfeed);
  1496. X        return (ret_code);
  1497. X    }
  1498. X
  1499. X    start_line_offset = 4;
  1500. X
  1501. X    wait_message (txt_post_a_followup);
  1502. X    
  1503. X    if (*note_h_followup && strcmp (note_h_followup, "poster") == 0) {
  1504. X        clear_message ();
  1505. X        if (! prompt_yn (LINES, txt_resp_to_poster, 'y')) {
  1506. X            return (ret_code);
  1507. X        }
  1508. X        *note_h_followup = '\0';
  1509. X    } else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
  1510. X        MoveCursor (LINES/2, 0);
  1511. X        CleartoEOS ();
  1512. X        center_line ((LINES/2)+2, TRUE, txt_resp_redirect);
  1513. X        MoveCursor ((LINES/2)+4, 0);
  1514. X
  1515. X        fputs ("    ", stdout);
  1516. X        ptr = note_h_followup;
  1517. X        while (*ptr) {
  1518. X            if (*ptr != ',') {
  1519. X                fputc (*ptr, stdout);
  1520. X            } else {
  1521. X                fputs ("\r\n    ", stdout);
  1522. X            }
  1523. X            fflush (stdout);
  1524. X            ptr++;
  1525. X        }
  1526. X
  1527. X        if (! prompt_yn (LINES, txt_continue, 'y')) {
  1528. X            return (ret_code);
  1529. X        }
  1530. X    }
  1531. X
  1532. X    if ((fp = fopen (article, "w")) == NULL) {
  1533. X        perror_message (txt_cannot_open, article);
  1534. X        return (ret_code);
  1535. X    }
  1536. X    chmod (article, 0600);
  1537. X
  1538. X    fprintf (fp, "Subject: Re: %s\n", eat_re (note_h_subj));
  1539. X
  1540. X    if (*note_h_followup && strcmp(note_h_followup, "poster") != 0) {
  1541. X        fprintf (fp, "Newsgroups: %s\n", note_h_followup);
  1542. X    } else {
  1543. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  1544. X    }
  1545. X
  1546. X    fprintf (fp, "References: %s\n", note_h_messageid);
  1547. X
  1548. X    if (*my_org) {
  1549. X        fprintf (fp, "Organization: %s\n", my_org);
  1550. X        start_line_offset++;
  1551. X    }
  1552. X    if (*reply_to) {
  1553. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1554. X        start_line_offset++;
  1555. X    }
  1556. X    if (note_h_distrib != '\0') {
  1557. X        fprintf (fp, "Distribution: %s\n", note_h_distrib);
  1558. X        start_line_offset++;
  1559. X    }
  1560. X    fprintf (fp, "\n");
  1561. X
  1562. X    if (copy_text) {    /* if "copy_text" */
  1563. X        if (arts[respnum].from != (char *) 0) {     
  1564. X            if (arts[respnum].name == arts[respnum].from) {     
  1565. X                fprintf (fp, txt_writes, arts[respnum].from);
  1566. X            } else {
  1567. X                fprintf (fp, txt_writes_name, arts[respnum].from, arts[respnum].name);
  1568. X            }
  1569. X        }
  1570. X        fseek (note_fp, note_mark[0], 0);
  1571. X        copy_fp (note_fp, fp, DEFAULT_COMMENT);
  1572. X    }
  1573. X
  1574. X    add_signature (fp, FALSE);
  1575. X    fclose (fp);
  1576. X
  1577. X    ch = 'e';
  1578. X    while (1) {
  1579. X        switch (ch) {
  1580. X        case 'e':
  1581. X            invoke_editor (article);
  1582. X            ret_code = POSTED_REDRAW;
  1583. X            break;
  1584. X
  1585. X        case 'q':
  1586. X        case ESC:
  1587. X            if (unlink_article)
  1588. X                unlink (article);
  1589. X            clear_message ();
  1590. X            return (ret_code);
  1591. X
  1592. X        case 'p':
  1593. X            wait_message (txt_posting);
  1594. X            if (submit_file (article)) {
  1595. X                ret_code = POSTED_OK;
  1596. X                info_message (txt_art_posted);
  1597. X                goto post_response_done;
  1598. X            } else {
  1599. X                rename_file (article, dead_article);
  1600. X                sprintf (buf, txt_art_rejected, dead_article);
  1601. X                info_message (buf);
  1602. X                sleep (3);
  1603. X                return (ret_code);
  1604. X            }
  1605. X        }
  1606. X
  1607. X        do {
  1608. X            sprintf (msg, "%s%c", txt_quit_edit_post, ch_default);
  1609. X            wait_message (msg);
  1610. X            MoveCursor(LINES, (int) strlen (txt_quit_edit_post));
  1611. X            if ((ch = (char) ReadCh()) == CR)
  1612. X                ch = ch_default;
  1613. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 'p');
  1614. X    }
  1615. X
  1616. Xpost_response_done:
  1617. X    if (*note_h_followup && strcmp(note_h_followup, "poster") != 0) {
  1618. X        find_mail_header (HEADER_SUBJECT, article, buf);
  1619. X        update_art_posted_file (note_h_followup, 'f', buf);
  1620. X    } else {
  1621. X        find_mail_header (HEADER_SUBJECT, article, buf);
  1622. X        update_art_posted_file (note_h_newsgroups, 'f', buf);
  1623. X    }
  1624. X    /*
  1625. X     * Update default posting prompt
  1626. X     */
  1627. X    my_strncpy (default_post_subject, buf, sizeof (default_post_subject));
  1628. X
  1629. X    if (unlink_article) {
  1630. X        unlink (article);
  1631. X    }
  1632. X    
  1633. X    return (ret_code);
  1634. X}
  1635. X
  1636. X
  1637. Xint mail_to_someone (address, confirm_to_mail, mailed_ok)
  1638. X    char *address;
  1639. X    int confirm_to_mail;
  1640. X    int *mailed_ok;
  1641. X{
  1642. X    char nam[100];
  1643. X    char ch = 's';
  1644. X    char ch_default = 's';
  1645. X    char buf[LEN];
  1646. X    char mail_to[LEN];
  1647. X    FILE *fp;
  1648. X    int redraw_screen = FALSE;
  1649. X
  1650. X    start_line_offset = 4;
  1651. X    
  1652. X    strcpy (mail_to, address);
  1653. X    clear_message ();
  1654. X    
  1655. X    sprintf (nam, "%s/.letter", homedir);
  1656. X    if ((fp = fopen (nam, "w")) == NULL) {
  1657. X        perror_message (txt_cannot_open, nam);
  1658. X        return (redraw_screen);
  1659. X    }
  1660. X    chmod (nam, 0600);
  1661. X
  1662. X    fprintf (fp, "To: %s\n", mail_to);
  1663. X    fprintf (fp, "Subject: (fwd) %s\n", note_h_subj);
  1664. X    if (*note_h_followup) {
  1665. X        fprintf (fp, "Newsgroups: %s\n\n", note_h_followup);
  1666. X    } else {
  1667. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  1668. X    }
  1669. X    if (*my_org) {
  1670. X        fprintf (fp, "Organization: %s\n", my_org);
  1671. X        start_line_offset++;
  1672. X    }
  1673. X    if (*reply_to) {
  1674. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1675. X        start_line_offset++;
  1676. X    }
  1677. X    fputc ('\n', fp);
  1678. X    
  1679. X    fseek (note_fp, 0L, 0);
  1680. X    copy_fp (note_fp, fp, "");
  1681. X
  1682. X    add_signature (fp, TRUE);
  1683. X    fclose (fp);
  1684. X    
  1685. X    while (1) {
  1686. X        if (confirm_to_mail) {
  1687. X            do {
  1688. X                sprintf (msg, "%s [%.*s]: %c", txt_quit_edit_send, 
  1689. X                    COLS-30, note_h_subj, ch_default);
  1690. X                wait_message (msg);
  1691. X                MoveCursor (LINES, (int) (strlen (msg)-1));
  1692. X                if ((ch = (char) ReadCh ()) == CR)
  1693. X                    ch = ch_default;
  1694. X            } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 's');
  1695. X        }
  1696. X        switch (ch) {
  1697. X        case 'e':
  1698. X            invoke_editor (nam);
  1699. X            redraw_screen = TRUE;
  1700. X            break;
  1701. X
  1702. X        case 'q':
  1703. X        case ESC:
  1704. X            unlink (nam);
  1705. X            clear_message ();
  1706. X            *mailed_ok = FALSE;
  1707. X            return (redraw_screen);
  1708. X
  1709. X        case 's':
  1710. X            /*
  1711. X             *  Open letter and get the To: line in case they changed
  1712. X             *  it with the editor
  1713. X             */
  1714. X            find_mail_header (HEADER_TO, nam, mail_to);
  1715. X            sprintf (msg, txt_mailing_to, mail_to);
  1716. X            wait_message (msg);
  1717. X            sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  1718. X            if (invoke_cmd (buf)) {
  1719. X                goto mail_to_someone_done;
  1720. X            } else {
  1721. X                error_message (txt_command_failed_s, buf);
  1722. X                *mailed_ok = FALSE;
  1723. X                break;
  1724. X            }
  1725. X        }
  1726. X    }
  1727. X
  1728. Xmail_to_someone_done:
  1729. X    unlink (nam);
  1730. X    *mailed_ok = TRUE;
  1731. X    return (redraw_screen);
  1732. X}
  1733. X
  1734. X
  1735. Xint mail_bug_report ()
  1736. X{
  1737. X    char nam[100];
  1738. X    char ch;
  1739. X    char ch_default = 's';
  1740. X    char buf[LEN];
  1741. X    char mail_to[LEN];
  1742. X    FILE *fp;
  1743. X    FILE *fp_uname;
  1744. X    int is_nntp = FALSE;
  1745. X    int is_nntp_only   = FALSE;
  1746. X    int is_longfiles   = FALSE;
  1747. X    int is_resync_active = 0;
  1748. X    int uname_ok = FALSE;
  1749. X
  1750. X    start_line_offset = 5;
  1751. X    
  1752. X    wait_message (txt_mail_bug_report);
  1753. X    
  1754. X    sprintf (nam, "%s/.bugreport", homedir);
  1755. X    if ((fp = fopen (nam, "w")) == NULL) {
  1756. X        perror_message (txt_cannot_open, nam);
  1757. X        return FALSE;
  1758. X    }
  1759. X    chmod(nam, 0600);
  1760. X
  1761. X    fprintf (fp, "To: %s\n", bug_addr);
  1762. X    fprintf (fp, "Subject: BUG REPORT %s %s PL%d %s\n",    progname,
  1763. X        VERSION, PATCHLEVEL, (compiled_with_nntp ? "(NNTP)" : ""));
  1764. X    if (*my_org) {
  1765. X        fprintf (fp, "Organization: %s\n", my_org);
  1766. X        start_line_offset++;
  1767. X    }
  1768. X    if (*reply_to) {
  1769. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1770. X        start_line_offset++;
  1771. X    }
  1772. X
  1773. X    if ((fp_uname = (FILE *) popen ("uname -a", "r")) != NULL) {
  1774. X        while (fgets (buf, sizeof (buf), fp_uname) != NULL) {
  1775. X            fprintf (fp, "\nBOX1: %s", buf);
  1776. X            start_line_offset += 2;
  1777. X            uname_ok = TRUE;
  1778. X        }
  1779. X        fclose (fp_uname);
  1780. X    }
  1781. X    if (! uname_ok) {
  1782. X        fprintf (fp, "\nPlease enter the following information:\n");
  1783. X        fprintf (fp, "BOX1: Machine+OS:\n");
  1784. X    }
  1785. X#ifndef NO_RESYNC_ACTIVE_FILE
  1786. X    is_resync_active = RESYNC_ACTIVE_SECS;
  1787. X#endif
  1788. X#ifdef USE_LONG_FILENAMES
  1789. X    is_longfiles = TRUE;
  1790. X#endif
  1791. X#ifdef NNTP_ABLE
  1792. X    is_nntp = TRUE;
  1793. X#endif
  1794. X#ifdef NNTP_ONLY
  1795. X    is_nntp_only = TRUE;
  1796. X#endif
  1797. X    fprintf (fp, "\nCFG1: active=%d  arts=%d  resync=%d  longfilenames=%d  nntp=%d\n\
  1798. XCFG2: nntp_only=%d  nntp_xuser=%d  nntp_xindex=%d  nntp_xspooldir=%d\n",
  1799. X        DEFAULT_ACTIVE_NUM,DEFAULT_ARTICLE_NUM,is_resync_active,
  1800. X        is_longfiles,  is_nntp,  is_nntp_only,  xuser_supported,
  1801. X        xindex_supported, xspooldir_supported);
  1802. X    start_line_offset += 2;
  1803. X    
  1804. X    fprintf (fp, "\nPlease enter bug report/gripe/comment:\n");
  1805. X
  1806. X    add_signature (fp, TRUE);
  1807. X    fclose (fp);
  1808. X    
  1809. X    ch = 'e';
  1810. X    while (1) {
  1811. X        switch (ch) {
  1812. X        case 'e':
  1813. X            invoke_editor (nam);
  1814. X            break;
  1815. X
  1816. X        case 'q':
  1817. X        case ESC:
  1818. X            unlink (nam);
  1819. X            clear_message ();
  1820. X            return TRUE;
  1821. X
  1822. X        case 's':
  1823. X            sprintf (msg, txt_mail_bug_report_confirm, bug_addr);
  1824. X            if (prompt_yn (LINES, msg, 'y')) {
  1825. X                strcpy (mail_to, bug_addr);
  1826. X                find_mail_header (HEADER_TO, nam, mail_to);
  1827. X                sprintf (msg, txt_mailing_to, mail_to);
  1828. X                wait_message (msg);
  1829. X                sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  1830. X                if (invoke_cmd (buf)) {
  1831. X                    sprintf (msg, txt_mailed, 1);
  1832. X                    info_message (msg);
  1833. X                    goto mail_bug_report_done;
  1834. X                } else {
  1835. X                    error_message (txt_command_failed_s, buf);
  1836. X                    break;
  1837. X                }
  1838. X            } else {
  1839. X                goto mail_bug_report_done;
  1840. X            }
  1841. X        }
  1842. X
  1843. X        do {
  1844. X            sprintf (msg, "%s: %c", txt_quit_edit_send, ch_default);
  1845. X            wait_message (msg);
  1846. X            MoveCursor (LINES, (int) strlen (msg)-1);
  1847. X            if ((ch = (char) ReadCh ()) == CR)
  1848. X                ch = ch_default;
  1849. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 's');
  1850. X    }
  1851. X
  1852. Xmail_bug_report_done:
  1853. X    unlink (nam);
  1854. X
  1855. X    return TRUE;
  1856. X}
  1857. X
  1858. X
  1859. Xint mail_to_author (group, respnum, copy_text)
  1860. X    char *group;
  1861. X    int respnum;
  1862. X    int copy_text;
  1863. X{
  1864. X    char buf[LEN];
  1865. X    char from_addr[LEN];
  1866. X    char nam[100];
  1867. X    char mail_to[LEN];
  1868. X    char ch, ch_default = 's';
  1869. X    FILE *fp;
  1870. X    int redraw_screen = FALSE;
  1871. X
  1872. X    start_line_offset = 4;
  1873. X    
  1874. X    wait_message (txt_reply_to_author);
  1875. X
  1876. X    sprintf (nam, "%s/.letter", homedir);
  1877. X    if ((fp = fopen (nam, "w")) == NULL) {
  1878. X        perror_message (txt_cannot_open, nam);
  1879. X        return (redraw_screen);
  1880. X    }
  1881. X    chmod (nam, 0600);
  1882. X
  1883. X    find_reply_to_addr (respnum, from_addr);
  1884. X
  1885. X    fprintf (fp, "To: %s\n", from_addr);
  1886. X    fprintf (fp, "Subject: Re: %s\n", eat_re(note_h_subj) );
  1887. X    fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  1888. X    if (*my_org) {
  1889. X        fprintf (fp, "Organization: %s\n", my_org);
  1890. X        start_line_offset++;
  1891. X    }
  1892. X    if (*reply_to) {
  1893. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  1894. X        start_line_offset++;
  1895. X    }
  1896. X    fputc ('\n', fp);
  1897. X
  1898. X    if (copy_text) {        /* if "copy_text" */
  1899. X        fprintf (fp, txt_in_art_you_write, note_h_messageid);
  1900. X        fseek (note_fp, note_mark[0], 0);
  1901. X        copy_fp (note_fp, fp, DEFAULT_COMMENT);
  1902. X    }
  1903. X
  1904. X    add_signature (fp, TRUE);
  1905. X    fclose (fp);
  1906. X
  1907. X    ch = 'e';
  1908. X    while (1) {
  1909. X        switch (ch) {
  1910. X        case 'e':
  1911. X            invoke_editor (nam);
  1912. X            redraw_screen = TRUE;
  1913. X            break;
  1914. X
  1915. X        case 'q':
  1916. X        case ESC:
  1917. X            unlink (nam);
  1918. X            clear_message ();
  1919. X            return (redraw_screen);
  1920. X
  1921. X        case 's':
  1922. X            my_strncpy (mail_to, arts[respnum].from, sizeof (mail_to));
  1923. X            find_mail_header (HEADER_TO, nam, mail_to);
  1924. X            sprintf (msg, txt_mailing_to, mail_to);
  1925. X            wait_message (msg);
  1926. X            sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam);
  1927. X            if (invoke_cmd (buf)) {
  1928. X                sprintf (msg, txt_mailed, 1);
  1929. X                info_message (msg);
  1930. X                goto mail_to_author_done;
  1931. X            } else {
  1932. X                error_message (txt_command_failed_s, buf);
  1933. X                break;
  1934. X            }
  1935. X        }
  1936. X
  1937. X        do {
  1938. X            sprintf (msg, "%s: %c", txt_quit_edit_send, ch_default);
  1939. X            wait_message (msg);
  1940. X            MoveCursor (LINES, (int) strlen (msg)-1);
  1941. X            if ((ch = (char) ReadCh ()) == CR)
  1942. X                ch = ch_default;
  1943. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 's');
  1944. X    }
  1945. X
  1946. Xmail_to_author_done:
  1947. X    find_mail_header (HEADER_SUBJECT, nam, buf);
  1948. X    unlink (nam);
  1949. X    update_art_posted_file (group, 'r', buf);
  1950. X
  1951. X    return (redraw_screen);
  1952. X}
  1953. X
  1954. X/*
  1955. X *  Read a file grabbing the value of the specified mail header line
  1956. X */
  1957. X
  1958. Xvoid find_mail_header (header, file, value)
  1959. X    int header;
  1960. X    char *file;
  1961. X    char *value;
  1962. X{
  1963. X    FILE *fp;
  1964. X    char buf[LEN];
  1965. X    char buf2[LEN];
  1966. X    char new_value[LEN];
  1967. X    char *p;
  1968. X
  1969. X    *new_value = '\0';
  1970. X
  1971. X    if ((fp = fopen (file, "r")) == NULL) {
  1972. X        perror_message (txt_cannot_open, file);
  1973. X        return;
  1974. X    }
  1975. X
  1976. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  1977. X        for (p = buf; *p && *p != '\n'; p++)
  1978. X            continue;
  1979. X        *p = '\0';
  1980. X
  1981. X        if (*buf == '\0')
  1982. X            break;
  1983. X
  1984. X        switch (header) {
  1985. X            case HEADER_TO:
  1986. X                if (strncmp (buf, "To: ", 4) == 0 ||
  1987. X                    strncmp (buf, "Cc: ", 4) == 0) {
  1988. X                    my_strncpy (buf2, &buf[4], sizeof (buf2));
  1989. X                    yank_to_addr (buf2, new_value);
  1990. X                } 
  1991. X                break;
  1992. X
  1993. X            case HEADER_SUBJECT:
  1994. X                if (strncmp (buf, "Subject: ", 9) == 0) {
  1995. X                    my_strncpy (new_value, &buf[9], sizeof (new_value));
  1996. X                }
  1997. X                break;
  1998. X        }
  1999. X    }
  2000. X
  2001. X    fclose (fp);
  2002. X
  2003. X    if (new_value[0] == ' ') {
  2004. X        strcpy (value, &new_value[1]);
  2005. X    } else {
  2006. X        strcpy (value, new_value);
  2007. X    }
  2008. X}
  2009. X
  2010. X
  2011. Xint cancel_article (group, respnum)
  2012. X    char *group;
  2013. X    int respnum;
  2014. X{
  2015. X    char ch, ch_default = 'c';
  2016. X    char buf[LEN];
  2017. X    char cancel[PATH_LEN];
  2018. X    char from[PATH_LEN];
  2019. X    FILE *fp;
  2020. X    int redraw_screen = FALSE;
  2021. X
  2022. X    /*
  2023. X     * Don't allow if not active news feed 
  2024. X     */
  2025. X    if (! spooldir_is_active) {
  2026. X        info_message (txt_not_active_newsfeed);
  2027. X        return (redraw_screen);
  2028. X    }
  2029. X
  2030. X    start_line_offset = 4;
  2031. X
  2032. X    get_from_name (cancel);
  2033. X
  2034. X    if (arts[respnum].from != arts[respnum].name) {
  2035. X        sprintf (from, "%s (%s)", arts[respnum].from, arts[respnum].name);
  2036. X    } else {
  2037. X        my_strncpy (from, arts[respnum].from, sizeof (from));
  2038. X    }
  2039. X
  2040. X    if (debug == 2) {
  2041. X        sprintf (msg, "From=[%s]  Cancel=[%s]", from, cancel);        
  2042. X        error_message (msg, "");
  2043. X    }
  2044. X    
  2045. X    if (strcmp (from, cancel) != 0) {
  2046. X        info_message (txt_art_cannot_cancel);
  2047. X        return (redraw_screen);
  2048. X    }
  2049. X            
  2050. X    clear_message ();
  2051. X    
  2052. X    sprintf (cancel, "%s/.cancel", homedir);
  2053. X    if ((fp = fopen (cancel, "w")) == NULL) {
  2054. X        perror_message (txt_cannot_open, cancel);
  2055. X        return (redraw_screen);
  2056. X    }
  2057. X    chmod (cancel, 0600);
  2058. X
  2059. X    fprintf (fp, "Subject: cancel %s\n", note_h_messageid);
  2060. X    if (*note_h_followup) {
  2061. X        fprintf (fp, "Newsgroups: %s\n", note_h_followup);
  2062. X    } else {
  2063. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  2064. X    }
  2065. X    fprintf (fp, "Control: cancel %s\n", note_h_messageid);
  2066. X    if (*my_org) { 
  2067. X        fprintf (fp, "Organization: %s\n", my_org);
  2068. X        start_line_offset++;    
  2069. X    }
  2070. X    if (*reply_to) {
  2071. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  2072. X        start_line_offset++;    
  2073. X    }
  2074. X    fputc ('\n', fp);
  2075. X
  2076. X    fprintf (fp, "Article cancelled from within tin\n");
  2077. X    
  2078. X    fclose (fp);
  2079. X    
  2080. X    while (1) {
  2081. X        do {
  2082. X            sprintf (msg, "%s [%.*s]: %c", txt_quit_edit_cancel,
  2083. X                COLS-30, note_h_subj, ch_default);
  2084. X            wait_message (msg);
  2085. X            MoveCursor (LINES, (int) strlen (msg)-1);
  2086. X            if ((ch = (char) ReadCh ()) == CR)
  2087. X                ch = ch_default;
  2088. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 'c');
  2089. X
  2090. X        switch (ch) {
  2091. X        case 'e':
  2092. X            invoke_editor (cancel);
  2093. X            redraw_screen = TRUE;
  2094. X            break;
  2095. X
  2096. X        case 'q':
  2097. X        case ESC:
  2098. X            unlink (cancel);
  2099. X            clear_message ();
  2100. X            return (redraw_screen);
  2101. X
  2102. X        case 'c':
  2103. X            wait_message (txt_cancelling);
  2104. X            if (submit_file (cancel)) {
  2105. X                info_message (txt_art_cancelled);
  2106. X                goto cancel_article_done;
  2107. X            } else {
  2108. X                error_message (txt_command_failed_s, cancel);
  2109. X                break;
  2110. X            }
  2111. X        }
  2112. X    }
  2113. X
  2114. Xcancel_article_done:
  2115. X    find_mail_header (HEADER_SUBJECT, cancel, buf);
  2116. X    unlink (cancel);
  2117. X    update_art_posted_file (group, 'c', buf);
  2118. X
  2119. X    return (redraw_screen);
  2120. X}
  2121. X
  2122. X/*
  2123. X * Crosspost an already existing article to another group (ie. local group)
  2124. X */
  2125. Xint crosspost_article (group, respnum)
  2126. X    char *group;
  2127. X    int respnum;
  2128. X{
  2129. X    char buf[LEN];
  2130. X    char ch;
  2131. X    char ch_default = 'p';
  2132. X    FILE *fp;
  2133. X    int ret_code = POSTED_NONE;
  2134. X    
  2135. X    start_line_offset = 4;
  2136. X
  2137. X    if ((fp = fopen (article, "w")) == NULL) {
  2138. X        perror_message (txt_cannot_open, article);
  2139. X        return (ret_code);
  2140. X    }
  2141. X    chmod (article, 0600);
  2142. X
  2143. X    fprintf (fp, "Subject: %s\n", eat_re (note_h_subj));
  2144. X    fprintf (fp, "Newsgroups: %s\n", group);
  2145. X
  2146. X    if (*my_org) {
  2147. X        fprintf (fp, "Organization: %s\n", my_org);
  2148. X        start_line_offset++;
  2149. X    }
  2150. X    if (*reply_to) {
  2151. X        fprintf (fp, "Reply-To: %s\n", reply_to);
  2152. X        start_line_offset++;
  2153. X    }
  2154. X    if (note_h_distrib != '\0') {
  2155. X        fprintf (fp, "Distribution: %s\n", note_h_distrib);
  2156. X        start_line_offset++;
  2157. X    }
  2158. X
  2159. X    fprintf (fp, "\n[ Article crossposted from %s ]", note_h_newsgroups);
  2160. X    get_author (FALSE, respnum, buf);
  2161. X    fprintf (fp, "\n[ Author was %s ]", buf);
  2162. X    fprintf (fp, "\n[ Posted on %s ]\n\n", note_h_date);
  2163. X  
  2164. X    fseek (note_fp, note_mark[0], 0);
  2165. X    copy_fp (note_fp, fp, "");
  2166. X
  2167. X    add_signature (fp, FALSE);
  2168. X    fclose (fp);
  2169. X
  2170. X    while (1) {
  2171. X        do {
  2172. X            sprintf (msg, txt_quit_edit_xpost, 
  2173. X                COLS-(strlen (txt_quit_edit_xpost)-1),
  2174. X                note_h_subj, ch_default);
  2175. X            wait_message (msg);
  2176. X            MoveCursor (LINES, (int) strlen (msg)-1);
  2177. X            if ((ch = (char) ReadCh ()) == CR)
  2178. X                ch = ch_default;
  2179. X        } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 'p');
  2180. X        switch (ch) {
  2181. X        case 'e':
  2182. X            invoke_editor (article);
  2183. X            ret_code = POSTED_REDRAW;
  2184. X            break;
  2185. X
  2186. X        case 'q':
  2187. X        case ESC:
  2188. X            if (unlink_article)
  2189. X                unlink (article);
  2190. X            clear_message ();
  2191. X            return (ret_code);
  2192. X
  2193. X        case 'p':
  2194. X            wait_message (txt_crosspost_an_article);
  2195. X            if (submit_file (article)) {
  2196. X                ret_code = POSTED_OK;
  2197. X                info_message (txt_art_posted);
  2198. X                goto crosspost_done;
  2199. X            } else {
  2200. X                rename_file (article, dead_article);
  2201. X                sprintf (buf, txt_art_rejected, dead_article);
  2202. X                info_message (buf);
  2203. X                sleep (3);
  2204. X                return (ret_code);
  2205. X            }
  2206. X        }
  2207. X    }
  2208. X
  2209. Xcrosspost_done:
  2210. X    find_mail_header (HEADER_SUBJECT, article, buf);
  2211. X    update_art_posted_file (group, 'x', buf);
  2212. X
  2213. X    if (unlink_article) {
  2214. X        unlink (article);
  2215. X    }
  2216. X    
  2217. X    return (ret_code);
  2218. X}
  2219. X
  2220. X
  2221. Xint submit_file (name)
  2222. X    char *name;
  2223. X{
  2224. X    char buf[LEN];
  2225. X    char *cp = buf;
  2226. X    int ret_code = FALSE;
  2227. X
  2228. X    insert_x_headers (name);
  2229. X
  2230. X    if (read_news_via_nntp) {
  2231. X#ifdef DEBUG
  2232. X        if (debug == 2) {
  2233. X            wait_message ("Using BUILTIN inews");
  2234. X            sleep (3);    
  2235. X        }
  2236. X#endif /* DEBUG */            
  2237. X        ret_code = submit_inews (name);
  2238. X    } else {
  2239. X#ifdef DEBUG
  2240. X        if (debug == 2) {
  2241. X            wait_message ("Using EXTERNAL inews");
  2242. X            sleep (3);    
  2243. X        }    
  2244. X#endif /* DEBUG */            
  2245. X#ifdef INEWSDIR
  2246. X        strcpy (buf, INEWSDIR);
  2247. X        strcat (buf, "/");
  2248. X        cp = &buf[strlen(buf)];
  2249. X#endif /* INEWSDIR */
  2250. X        sprintf (cp, "inews -h < %s %s", name, redirect_output);
  2251. X    
  2252. X        ret_code = invoke_cmd (buf);
  2253. X    } 
  2254. X
  2255. X    return (ret_code);
  2256. X}
  2257. X
  2258. X
  2259. Xvoid add_signature (fp, flag)
  2260. X    FILE *fp;
  2261. X    int flag;
  2262. X{
  2263. X    FILE *sigfp;
  2264. X
  2265. X    if (read_news_via_nntp) {
  2266. X#ifdef NNTP_INEWS
  2267. X        flag = TRUE;
  2268. X#endif
  2269. X    }
  2270. X
  2271. X    /*
  2272. X     * Use ~/.signature or ~/.Sig or custom .Sig files
  2273. X     */
  2274. X    if ((sigfp = fopen (default_signature, "r")) != NULL) {
  2275. X        if (flag) {
  2276. X            fprintf (fp, "\n--\n");
  2277. X            copy_fp (sigfp, fp, "");
  2278. X        }
  2279. X        fclose (sigfp);
  2280. X        return;
  2281. X    }
  2282. X
  2283. X    if ((sigfp = fopen (active[my_group[cur_groupnum]].attribute.sigfile, "r")) != NULL) {
  2284. X        fprintf (fp, "\n--\n");
  2285. X        copy_fp (sigfp, fp, "");
  2286. X        fclose (sigfp);
  2287. X    }
  2288. X}
  2289. X
  2290. X
  2291. Xvoid insert_x_headers (infile)
  2292. X    char *infile;
  2293. X{
  2294. X    char line[LEN];
  2295. X    char outfile[PATH_LEN];
  2296. X    FILE *fp_in, *fp_out;
  2297. X    int gotit = FALSE;
  2298. X    
  2299. X    if ((fp_in = fopen (infile, "r")) != NULL) {
  2300. X        sprintf (outfile, "%s.%d", infile, process_id);
  2301. X        if ((fp_out = fopen (outfile, "w")) != NULL) {
  2302. X            while (fgets (line, sizeof (line), fp_in) != NULL) {
  2303. X                if (! gotit && line[0] == '\n') {
  2304. X                    fprintf (fp_out, "X-Newsreader: Tin %s PL%d\n\n",
  2305. X                        VERSION, PATCHLEVEL);
  2306. X                    gotit = TRUE;
  2307. X                } else {
  2308. X                    fputs (line, fp_out); 
  2309. X                }    
  2310. X            }
  2311. X            fclose (fp_out);
  2312. X            fclose (fp_in);
  2313. X            rename_file (outfile, infile);
  2314. X        }
  2315. X    }
  2316. X}
  2317. X
  2318. X
  2319. Xvoid find_reply_to_addr (respnum, from_addr)
  2320. X    int respnum;
  2321. X    char *from_addr;
  2322. X{
  2323. X    char buf[LEN];
  2324. X    int found = FALSE;
  2325. X    int len = 0;
  2326. X    long orig_offset;
  2327. X
  2328. X    orig_offset = ftell (note_fp);
  2329. X    fseek (note_fp, 0L, 0);
  2330. X    
  2331. X    while (fgets (buf, sizeof (buf), note_fp) != NULL && 
  2332. X        found == FALSE && buf[0] != '\n') {
  2333. X        if (strncmp (buf, "Reply-To: ", 10) == 0) {
  2334. X            strcpy (from_addr, &buf[10]);
  2335. X            len = strlen (from_addr);
  2336. X            from_addr[len-1] = '\0';
  2337. X            sprintf (buf, "%s%s", from_addr, add_addr);
  2338. X            strcpy (from_addr, buf);
  2339. X            found = TRUE;
  2340. X        }    
  2341. X    }
  2342. X
  2343. X    if (! found) {
  2344. X        if (arts[respnum].name != arts[respnum].from) { 
  2345. X            sprintf (buf, "%s%s (%s)",
  2346. X                 arts[respnum].from, add_addr,
  2347. X                 arts[respnum].name);
  2348. X            strcpy (from_addr, buf);
  2349. X        } else { 
  2350. X            sprintf (from_addr, "%s%s",
  2351. X                 arts[respnum].from, add_addr);
  2352. X        }    
  2353. X    }
  2354. X    
  2355. X    fseek (note_fp, orig_offset, 0);
  2356. X}
  2357. X        
  2358. END_OF_FILE
  2359.   if test 26765 -ne `wc -c <'post.c'`; then
  2360.     echo shar: \"'post.c'\" unpacked with wrong size!
  2361.   fi
  2362.   # end of 'post.c'
  2363. fi
  2364. echo shar: End of archive 6 \(of 14\).
  2365. cp /dev/null ark6isdone
  2366. MISSING=""
  2367. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2368.     if test ! -f ark${I}isdone ; then
  2369.     MISSING="${MISSING} ${I}"
  2370.     fi
  2371. done
  2372. if test "${MISSING}" = "" ; then
  2373.     echo You have unpacked all 14 archives.
  2374.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2375. else
  2376.     echo You still must unpack the following archives:
  2377.     echo "        " ${MISSING}
  2378. fi
  2379. exit 0
  2380. exit 0 # Just in case...
  2381.