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

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  3. Subject:  v30i010:  tin - threaded full screen newsreader, Part10/14
  4. Message-ID: <1992May20.172801.29797@sparky.imd.sterling.com>
  5. X-Md4-Signature: eae5d5239ebbb1bd3673b694fc6f423e
  6. Date: Wed, 20 May 1992 17:28:01 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 10
  11. Archive-name: tin/part10
  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:  feed.c misc.c nntplib.c wildmat.c
  22. # Wrapped by kent@sparky on Tue May 19 13:38:05 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 10 (of 14)."'
  26. if test -f 'feed.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'feed.c'\"
  28. else
  29.   echo shar: Extracting \"'feed.c'\" \(14936 characters\)
  30.   sed "s/^X//" >'feed.c' <<'END_OF_FILE'
  31. X/*
  32. X *  Project   : tin - a threaded Netnews reader
  33. X *  Module    : feed.c
  34. X *  Author    : I.Lea
  35. X *  Created   : 31-08-91
  36. X *  Updated   : 12-05-92
  37. X *  Notes     : provides same interface to mail,pipe,print and save commands
  38. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  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 *glob_group;            /* Group name */
  48. Xextern char note_h_date[LEN];        /* Date:    */
  49. Xextern char note_h_newsgroups[LEN];    /* Newsgroups:    */
  50. Xextern char note_h_subj[LEN];        /* Subject:    */
  51. Xextern FILE *note_fp;                /* the body of the current article */
  52. Xextern int note_end;                /* end of article ? */
  53. Xextern int note_page;                /* what page we're on */
  54. Xextern long note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  55. X
  56. Xchar default_mail_address[LEN];
  57. Xchar default_pipe_command[LEN];
  58. Xchar default_save_file[PATH_LEN];
  59. Xchar default_regex_pattern[LEN];
  60. Xchar default_crosspost_group[LEN];
  61. Xchar proc_ch_default;                /* set in change_rcfile () */
  62. X
  63. X
  64. Xvoid feed_articles (function, level, prompt, respnum, group_path)
  65. X    int function;
  66. X    int level;
  67. X    char *prompt;
  68. X    int respnum;
  69. X    char *group_path;
  70. X{
  71. X#ifndef INDEX_DAEMON
  72. X
  73. X    char address[LEN];
  74. X    char command[LEN];
  75. X    char filename[PATH_LEN], *p;
  76. X    char group[LEN];
  77. X    char mailbox[LEN];
  78. X    char pattern[LEN];
  79. X    char ch = 'a', ch_default = 'a';
  80. X    char proc_ch = proc_ch_default;
  81. X    FILE *fp = (FILE *) 0;
  82. X    int b, i, j;
  83. X    int confirm = TRUE;
  84. X    int processed_ok = TRUE;
  85. X    int proceed = FALSE;
  86. X    int is_mailbox = FALSE;
  87. X    int orig_note_end = 0;
  88. X    int orig_note_page = 0;
  89. X    int processed = 0;
  90. X    int ret1 = FALSE;
  91. X    int ret2 = FALSE;
  92. X    int redraw_screen = FALSE;
  93. X    
  94. X    if (level == PAGE_LEVEL) {
  95. X        orig_note_end = note_end;
  96. X        orig_note_page = note_page;
  97. X    }
  98. X
  99. X    b = which_thread (respnum);
  100. X
  101. X    /*
  102. X     * try and work out what default the user wants
  103. X     */
  104. X    if (num_of_tagged_arts) {
  105. X        ch_default = 'T';
  106. X    } else if (num_of_hot_arts) {
  107. X        ch_default = 'h';
  108. X    } else if (num_of_responses (b)) {
  109. X        ch_default = 't';
  110. X    }
  111. X
  112. X    if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0) ||
  113. X        (save_archive_name == TRUE && function != FEED_SAVE) ||
  114. X        ch_default == 'T') {
  115. X        do {
  116. X            sprintf (msg, "%s%s%c", prompt, txt_art_thread_regex_tag, ch_default);
  117. X            wait_message (msg);
  118. X            MoveCursor (LINES, (int) strlen (msg)-1);
  119. X            if ((ch = (char) ReadCh ()) == CR)
  120. X                ch = ch_default;
  121. X        } while (ch != ESC && ch != 'a' && ch != 't' && ch != 'T' && 
  122. X            ch != 'h' && ch != 'p' && ch != 'q');
  123. X    } else {
  124. X        filename[0] = '\0';
  125. X        ch = ch_default;
  126. X        if (proc_ch != 'n') {
  127. X            if (str_str (glob_group, "sources", 7)) {
  128. X                proc_ch = 's';        /* *source* group */ 
  129. X            } else if (str_str (glob_group, "binaries", 8)) {
  130. X                proc_ch = 'u';        /* *binaries* group */
  131. X            } else {
  132. X                proc_ch = 's';
  133. X            }
  134. X        }    
  135. X    }
  136. X
  137. X    if (ch == 'q' || ch == ESC) {    /* exit */
  138. X        clear_message ();
  139. X        return;
  140. X    }
  141. X    
  142. X    if (ch == 'p') {
  143. X        sprintf (msg, txt_feed_pattern, default_regex_pattern);
  144. X        if (! prompt_string (msg, pattern)) {
  145. X            clear_message ();
  146. X            return;
  147. X        }    
  148. X        if (strlen (pattern)) {
  149. X            my_strncpy (default_regex_pattern, pattern, 
  150. X                sizeof (default_regex_pattern));
  151. X        } else {
  152. X            if (default_regex_pattern[0]) {
  153. X                my_strncpy (pattern, default_regex_pattern, 
  154. X                    sizeof (default_regex_pattern));
  155. X            } else {
  156. X                info_message (txt_no_match);
  157. X                return;
  158. X            }
  159. X        }
  160. X    }
  161. X
  162. X    switch (function) {
  163. X        case FEED_MAIL:
  164. X            sprintf (msg, txt_mail_art_to, 
  165. X                COLS-(strlen(txt_mail_art_to)+30), default_mail_address);
  166. X            if (! prompt_string (msg, address)) {
  167. X                clear_message ();
  168. X                return;
  169. X            }    
  170. X            if (strlen (address)) {
  171. X                strcpy (default_mail_address, address);
  172. X            } else {
  173. X                if (default_mail_address[0]) {
  174. X                    strcpy (address, default_mail_address);
  175. X                } else {
  176. X                    info_message (txt_no_mail_address);    
  177. X                    return;
  178. X                }
  179. X            }
  180. X            break;
  181. X        case FEED_PIPE:
  182. X            sprintf (msg, txt_pipe_to_command, 
  183. X                COLS-(strlen(txt_pipe_to_command)+30), default_pipe_command);
  184. X            if (! prompt_string (msg, command)) {
  185. X                clear_message ();
  186. X                return;
  187. X            }
  188. X            if (strlen (command)) {
  189. X                strcpy (default_pipe_command, command);
  190. X            } else {
  191. X                if (default_pipe_command[0]) {
  192. X                    strcpy (command, default_pipe_command);
  193. X                } else {
  194. X                    info_message (txt_no_command);    
  195. X                    return;
  196. X                }
  197. X            }
  198. X
  199. X            if ((fp = (FILE *) popen (command, "w")) == NULL) {
  200. X                perror_message (txt_command_failed_s, command);
  201. X                return;
  202. X            }
  203. X            wait_message (txt_piping);
  204. X            Raw (FALSE);
  205. X            break;
  206. X        case FEED_PRINT:    
  207. X            if (default_printer) {
  208. X#ifdef sinix
  209. X                    sprintf (command, "%s -dru=%s %s",
  210. X                        printer, get_val ("PRINTER","ps"), redirect_output);
  211. X#else
  212. X                    sprintf (command, "%s -P%s %s",
  213. X                        printer, get_val ("PRINTER","ps"), redirect_output);
  214. X#endif
  215. X            } else {
  216. X                if (cmd_line_printer[0]) {
  217. X                    sprintf (command, "%s %s",
  218. X                        cmd_line_printer, redirect_output);
  219. X                } else {
  220. X                    sprintf (command, "%s %s",
  221. X                        printer, redirect_output);
  222. X                }
  223. X            }
  224. X            if ((fp = (FILE *) popen (command, "w")) == NULL) {
  225. X                perror_message (txt_command_failed_s, command);
  226. X                return;
  227. X            }
  228. X            break;
  229. X        case FEED_SAVE:        /* ask user for filename */
  230. X            free_save_array ();
  231. X            if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0)) {
  232. X                sprintf (msg, txt_save_filename, default_save_file);
  233. X                if (! prompt_string (msg, filename)) {
  234. X                    clear_message ();
  235. X                    return;
  236. X                }
  237. X                if (strlen (filename)) {
  238. X                    my_strncpy (default_save_file, filename,
  239. X                        sizeof (default_save_file));
  240. X                } else {
  241. X                    if (default_save_file[0]) {
  242. X                        my_strncpy (filename, default_save_file,
  243. X                            sizeof (filename));
  244. X                    } else {
  245. X                        info_message (txt_no_filename);    
  246. X                        return;
  247. X                    }
  248. X                }
  249. X                for (p = filename; *p && (*p == ' ' || *p == '\t'); p++) {
  250. X                    continue;
  251. X                }
  252. X                if (! *p) {
  253. X                    info_message (txt_no_filename);
  254. X                    return;
  255. X                }
  256. X                if ((filename[0] == '~' || filename[0] == '+') && strlen (filename) == 1) {
  257. X                    info_message (txt_no_filename);
  258. X                    return;
  259. X                }
  260. X                is_mailbox = create_path (filename);
  261. X                if (is_mailbox) {
  262. X                    if ((int) strlen (filename) > 1) {
  263. X                        my_strncpy (mailbox, filename+1, sizeof (mailbox));        
  264. X                    } else {
  265. X                        my_strncpy (mailbox, glob_group, sizeof (mailbox));
  266. X                        /*
  267. X                         *  convert 1st letter to uppercase
  268. X                         */
  269. X                        if (mailbox[0] >= 'a' && mailbox[0] <= 'z') {
  270. X                            mailbox[0] = mailbox[0] - 32;
  271. X                        }
  272. X                    }
  273. X                    my_strncpy (filename, mailbox, sizeof (filename));
  274. X                } else {        /* ask for post processing type */
  275. X                    do {
  276. X                        sprintf (msg, "%s%c", txt_post_process_type, proc_ch_default);
  277. X                        wait_message (msg);
  278. X                        MoveCursor (LINES, (int) strlen (msg)-1);
  279. X                        if ((proc_ch = (char) ReadCh ()) == CR)
  280. X                            proc_ch = proc_ch_default;
  281. X                    } while (proc_ch != 'n' && proc_ch != 's' &&
  282. X                         proc_ch != 'u' && proc_ch != 'U');
  283. X                }
  284. X            }
  285. X            clear_message ();
  286. X            break;
  287. X        case FEED_XPOST:    /* ask user for newsgroups */
  288. X            sprintf (msg, txt_crosspost_group, default_crosspost_group);
  289. X    
  290. X            if (! prompt_string (msg, group)) {
  291. X                clear_message ();
  292. X                return;
  293. X            }
  294. X
  295. X            if (strlen (group)) {
  296. X                my_strncpy (default_crosspost_group, group,
  297. X                    sizeof (default_crosspost_group));
  298. X            } else {
  299. X                if (default_crosspost_group[0]) {
  300. X                    my_strncpy (group, default_crosspost_group, 
  301. X                        sizeof (group));
  302. X                } else {
  303. X                    info_message (txt_no_group);
  304. X                    return;
  305. X                }
  306. X            }
  307. X            break;
  308. X    }
  309. X    
  310. X    switch (ch) {
  311. X        case 'a':        /* article */
  312. X            if (level == GROUP_LEVEL) {
  313. X                note_page = art_open (arts[respnum].artnum, group_path);    
  314. X            }
  315. X            switch (function) {
  316. X                case FEED_MAIL:
  317. X                    redraw_screen = mail_to_someone (address, TRUE, &processed_ok);
  318. X                    break;
  319. X                case FEED_PIPE:
  320. X                    fseek (note_fp, 0L, 0);
  321. X                    copy_fp (note_fp, fp, "");
  322. X                    break;
  323. X                case FEED_PRINT:
  324. X                    processed_ok = print_file (fp, respnum, 1);
  325. X                    pclose (fp);        
  326. X                    break;
  327. X                case FEED_SAVE:
  328. X                    wait_message (txt_saving);
  329. X                    add_to_save_list (0, &arts[respnum], is_mailbox, filename);
  330. X                    processed_ok = save_art_to_file (respnum, 0, FALSE, "");
  331. X                    break;
  332. X                case FEED_XPOST:
  333. X                    redraw_screen = crosspost_article (group, respnum);
  334. X                    break;
  335. X            }
  336. X            if (processed_ok) {
  337. X                processed++;
  338. X            }    
  339. X            if (mark_saved_read) {
  340. X                if (processed_ok) {
  341. X                    arts[respnum].unread = ART_READ;
  342. X                }
  343. X            }
  344. X            if (level == GROUP_LEVEL) {
  345. X                art_close ();
  346. X            }
  347. X            break;
  348. X            
  349. X        case 't':         /* thread */
  350. X            confirm = TRUE;
  351. X            for (i = (int) base[b]; i >= 0; i = arts[i].thread) {
  352. X                if (function == FEED_PRINT) {
  353. X                    if ((fp = (FILE *) popen (command, "w")) == NULL) {
  354. X                        perror_message (txt_command_failed_s, command);
  355. X                        return;
  356. X                    }
  357. X                }
  358. X                if (level == PAGE_LEVEL) {
  359. X                    art_close ();
  360. X                }
  361. X                note_page = art_open (arts[i].artnum, group_path);    
  362. X                switch (function) {
  363. X                    case FEED_MAIL:
  364. X                        processed_ok = TRUE;    
  365. X                        mail_to_someone (address, confirm, &processed_ok);
  366. X                        confirm = FALSE;
  367. X                        break;
  368. X                    case FEED_PIPE:
  369. X                        fseek (note_fp, 0L, 0);
  370. X                        copy_fp (note_fp, fp, "");
  371. X                        break;
  372. X                    case FEED_PRINT:
  373. X                        processed_ok = print_file (fp, i, processed+1);
  374. X                        pclose (fp);
  375. X                        break;
  376. X                    case FEED_SAVE:
  377. X                        add_to_save_list (i, &arts[i], is_mailbox, filename);
  378. X                        break;
  379. X                    case FEED_XPOST:
  380. X                        redraw_screen = crosspost_article (group, i);
  381. X                        break;
  382. X                }
  383. X                if (processed_ok) {
  384. X                    processed++;
  385. X                }
  386. X                if (mark_saved_read) {
  387. X                    if (processed_ok) {
  388. X                        arts[i].unread = ART_READ;
  389. X                    }    
  390. X                }
  391. X                art_close ();
  392. X            }
  393. X            if (function == FEED_SAVE) {
  394. X                sort_save_list ();
  395. X                (void) save_thread_to_file (is_mailbox, group_path);
  396. X            }
  397. X            break;
  398. X
  399. X        case 'T':         /* tagged articles */
  400. X            confirm = TRUE;
  401. X            for (i=1 ; i <= num_of_tagged_arts ; i++) {
  402. X                for (j=0 ; j < top ; j++) {
  403. X                    if (arts[j].tagged && arts[j].tagged == i) { 
  404. X
  405. X                        if (function == FEED_PRINT) {
  406. X                            if ((fp = (FILE *) popen (command, "w")) == NULL) {
  407. X                                perror_message (txt_command_failed_s, command);
  408. X                                return;
  409. X                            }
  410. X                        }
  411. X                        if (level == PAGE_LEVEL) {
  412. X                            art_close ();
  413. X                        }
  414. X                        note_page = art_open (arts[j].artnum, group_path);    
  415. X                        switch (function) {
  416. X                            case FEED_MAIL:
  417. X                                processed_ok = TRUE;
  418. X                                mail_to_someone (address, confirm, &processed_ok);
  419. X                                confirm = FALSE;
  420. X                                break;
  421. X                            case FEED_PIPE:
  422. X                                fseek (note_fp, 0L, 0);
  423. X                                copy_fp (note_fp, fp, "");
  424. X                                break;
  425. X                            case FEED_PRINT:
  426. X                                processed_ok = print_file (fp, j, processed+1);
  427. X                                pclose (fp);
  428. X                                break;
  429. X                            case FEED_SAVE:
  430. X                                add_to_save_list (j, &arts[j], is_mailbox, filename);
  431. X                                break;
  432. X                            case FEED_XPOST:
  433. X                                redraw_screen = crosspost_article (group, j);
  434. X                                break;
  435. X                        }
  436. X                        if (processed_ok) {
  437. X                            processed++;
  438. X                        }    
  439. X                        if (mark_saved_read) {
  440. X                            if (processed_ok) {
  441. X                                arts[j].unread = ART_READ;
  442. X                            }    
  443. X                        }
  444. X                        art_close ();
  445. X                    }
  446. X                }
  447. X            }
  448. X            if (function == FEED_SAVE) {                
  449. X                (void) save_regex_arts (is_mailbox, group_path);
  450. X            }
  451. X            untag_all_articles ();
  452. X            break;
  453. X
  454. X        case 'h':         /* hot (auto-selected) articles */
  455. X        case 'p':         /* regex pattern matched articles */
  456. X            confirm = TRUE;
  457. X            for (i = 0 ; i < top_base ; i++) {
  458. X                for (j = (int) base[i]; j >= 0; j = arts[j].thread) {
  459. X                    if (ch == 'p') {
  460. X                        if (STR_MATCH(arts[j].subject, pattern)) {
  461. X                            proceed = TRUE;
  462. X                        }
  463. X                    } else if (arts[j].hot) {
  464. X                        proceed = TRUE;
  465. X                    }                
  466. X                    if (proceed) {
  467. X                        proceed = FALSE;
  468. X                        if (function == FEED_PRINT) {
  469. X                            if ((fp = (FILE *) popen (command, "w")) == NULL) {
  470. X                                perror_message (txt_command_failed_s, command);
  471. X                                return;
  472. X                            }
  473. X                        }
  474. X                        if (level == PAGE_LEVEL) {
  475. X                            art_close ();
  476. X                        }
  477. X                        note_page = art_open (arts[j].artnum, group_path);    
  478. X                        switch (function) {
  479. X                            case FEED_MAIL:
  480. X                                processed_ok = TRUE;
  481. X                                mail_to_someone (address, confirm, &processed_ok);
  482. X                                /* confirm = FALSE; */
  483. X                                break;
  484. X                            case FEED_PIPE:
  485. X                                fseek (note_fp, 0L, 0);
  486. X                                copy_fp (note_fp, fp, "");
  487. X                                break;
  488. X                            case FEED_PRINT:
  489. X                                processed_ok = print_file (fp, j, processed+1);
  490. X                                pclose (fp);
  491. X                                break;
  492. X                            case FEED_SAVE:
  493. X                                sprintf (filename, "%s.%02d", filename, processed+1);
  494. X                                add_to_save_list (0, &arts[j], is_mailbox, filename);
  495. X                                processed_ok = save_art_to_file (respnum, 0, FALSE, "");
  496. X                                break;
  497. X                            case FEED_XPOST:
  498. X                                redraw_screen = crosspost_article (group, j);
  499. X                                break;
  500. X                        }
  501. X                        if (processed_ok) {
  502. X                            processed++;
  503. X                        }    
  504. X                        if (mark_saved_read) {
  505. X                            if (processed_ok) {
  506. X                                arts[j].unread = ART_READ;
  507. X                                if (ch == 'h') {
  508. X                                    arts[j].hot = FALSE;
  509. X                                    num_of_hot_arts--;
  510. X                                }    
  511. X                            }    
  512. X                        }
  513. X                         art_close ();
  514. X                    }
  515. X                }    
  516. X            }
  517. X            break;
  518. X    }
  519. X
  520. X    redraw_screen = mail_check ();    /* in case of sending to oneself */
  521. X
  522. X    switch (function) {
  523. X        case FEED_PIPE:
  524. X            pclose (fp);        
  525. X            Raw (TRUE);
  526. X            continue_prompt ();
  527. X            redraw_screen = TRUE;
  528. X            break;
  529. X        case FEED_SAVE:
  530. X            if (proc_ch != 'n' && is_mailbox == FALSE) {
  531. X                ret2 = post_process_files (proc_ch);
  532. X            }
  533. X            free_save_array ();
  534. X            break;
  535. X    }
  536. X
  537. X    if (level == GROUP_LEVEL) {
  538. X        ret1 = (mark_saved_read ? TRUE : FALSE);
  539. X    }
  540. X    if ((ret1 || ret2) && is_mailbox == FALSE) {
  541. X        redraw_screen = TRUE;
  542. X    }
  543. X
  544. X    if (level == PAGE_LEVEL) {
  545. X        if (ch != 'a') {
  546. X            note_page = art_open (arts[respnum].artnum, group_path);
  547. X        }
  548. X        note_end = orig_note_end;
  549. X        note_page = orig_note_page;
  550. X        fseek (note_fp, note_mark[note_page], 0);
  551. X        if (redraw_screen) {
  552. X            if (note_page == 0) {
  553. X                show_note_page (respnum, glob_group);
  554. X            } else {
  555. X                redraw_page (respnum, glob_group);
  556. X            }
  557. X        } else {
  558. X            if (function == FEED_PIPE) {
  559. X                clear_message ();
  560. X            }
  561. X        }
  562. X    } else {
  563. X        if (redraw_screen) {
  564. X            show_group_page (glob_group);
  565. X        }
  566. X    }
  567. X    if (function == FEED_MAIL) {    
  568. X        sprintf (msg, txt_mailed, processed);
  569. X        info_message (msg);
  570. X    } else if (function == FEED_PRINT) {    
  571. X        sprintf (msg, txt_printed, processed);
  572. X        info_message (msg);
  573. X    } else if (function == FEED_SAVE) {    
  574. X        if (ch == 'a') {
  575. X            sprintf (msg, txt_saved, processed);
  576. X            info_message (msg);
  577. X        }    
  578. X    }
  579. X
  580. X#endif /* INDEX_DAEMON */
  581. X}
  582. X
  583. X
  584. Xint print_file (fp, respnum, count)
  585. X    FILE *fp;
  586. X    int respnum;
  587. X    int count;
  588. X{                            
  589. X    sprintf (msg, "%s%d", txt_printing, count);
  590. X    wait_message (msg);
  591. X    
  592. X    if (print_header) {
  593. X        fseek(note_fp, 0L, 0);
  594. X    } else {
  595. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  596. X        if (arts[respnum].from == arts[respnum].name) {
  597. X            fprintf (fp, "From: %s\n", arts[respnum].from);
  598. X        } else {
  599. X            fprintf (fp, "From: %s (%s)\n",
  600. X                arts[respnum].from, arts[respnum].name);
  601. X        }        
  602. X        fprintf (fp, "Subject: %s\n", note_h_subj);
  603. X        fprintf (fp, "Date: %s\n\n", note_h_date);
  604. X        fseek (note_fp, note_mark[0], 0);
  605. X    }
  606. X    copy_fp (note_fp, fp, "");
  607. X
  608. X    return (TRUE);    /* a hack that will check if file was really checked later */
  609. X}                        
  610. END_OF_FILE
  611.   if test 14936 -ne `wc -c <'feed.c'`; then
  612.     echo shar: \"'feed.c'\" unpacked with wrong size!
  613.   fi
  614.   # end of 'feed.c'
  615. fi
  616. if test -f 'misc.c' -a "${1}" != "-c" ; then 
  617.   echo shar: Will not clobber existing file \"'misc.c'\"
  618. else
  619.   echo shar: Extracting \"'misc.c'\" \(15398 characters\)
  620.   sed "s/^X//" >'misc.c' <<'END_OF_FILE'
  621. X/*
  622. X *  Project   : tin - a threaded Netnews reader
  623. X *  Module    : misc.c
  624. X *  Author    : I.Lea & R.Skrenta
  625. X *  Created   : 01-04-91
  626. X *  Updated   : 10-05-92
  627. X *  Notes     :
  628. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  629. X *              You may  freely  copy or  redistribute  this software,
  630. X *              so  long as there is no profit made from its use, sale
  631. X *              trade or  reproduction.  You may not change this copy-
  632. X *              right notice, and it must be included in any copy made
  633. X */
  634. X
  635. X#include    "tin.h"
  636. X
  637. Xstatic char *mailbox_name = (char *) 0;
  638. Xstatic int  mailbox_size;
  639. X
  640. X
  641. Xvoid asfail (file, line, cond)
  642. X    char    *file;
  643. X    int    line;
  644. X    char    *cond;
  645. X{
  646. X      fprintf (stderr, "%s: assertion failure: %s (%d): %s\n",
  647. X          progname, file, line, cond);
  648. X      fflush (stderr);
  649. X      
  650. X     /*
  651. X      * create a core dump
  652. X      */
  653. X#ifdef SIGABRT    
  654. X    sigdisp(SIGABRT, SIG_DFL);
  655. X     kill (process_id, SIGABRT);
  656. X#else
  657. X#    ifdef SIGILL
  658. X        sigdisp(SIGILL, SIG_DFL);
  659. X         kill (process_id, SIGILL);
  660. X#    else
  661. X#        ifdef SIGIOT
  662. X            sigdisp(SIGIOT, SIG_DFL);
  663. X             kill (process_id, SIGIOT);
  664. X#        endif
  665. X#    endif
  666. X#endif
  667. X    exit(1);
  668. X}
  669. X
  670. X
  671. Xvoid copy_fp (fp_ip, fp_op, prefix)
  672. X    FILE *fp_ip;
  673. X    FILE *fp_op;
  674. X    char *prefix;
  675. X{
  676. X    extern int errno;
  677. X    char buf[8192];
  678. X
  679. X    while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  680. X        if (fprintf (fp_op, "%s%s", prefix, buf) == EOF) {
  681. X            if (errno == EPIPE) {
  682. X                return;
  683. X            }
  684. X            sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  685. X            perror_message (msg, "");
  686. X        }
  687. X    }
  688. X}
  689. X
  690. X
  691. Xchar *get_val (env, def)
  692. X    char *env;        /* Environment variable we're looking for    */
  693. X    char *def;        /* Default value if no environ value found    */
  694. X{
  695. X    char *ptr;
  696. X
  697. X    if ((ptr = (char *) getenv(env)) != NULL)
  698. X        return (ptr);
  699. X    else
  700. X        return (def);
  701. X}
  702. X
  703. X
  704. Xint invoke_editor (nam)
  705. X    char *nam;
  706. X{
  707. X    char buf[LEN];
  708. X    char *my_editor;
  709. X    static char editor[LEN];
  710. X    static int first = TRUE;
  711. X
  712. X    if (first) {
  713. X        my_editor = (char *) getenv ("VISUAL");
  714. X
  715. X        strcpy (editor, my_editor != NULL ? my_editor : get_val ("EDITOR", DEFAULT_EDITOR));
  716. X        first = FALSE;
  717. X    }
  718. X
  719. X    if (start_editor_offset) {
  720. X        sprintf (buf, "%s +%d %s", editor, start_line_offset, nam);
  721. X    } else {
  722. X        sprintf (buf, "%s %s", editor, nam);
  723. X    }
  724. X
  725. X    wait_message (buf);
  726. X
  727. X    return invoke_cmd (buf);
  728. X}
  729. X
  730. X
  731. Xvoid shell_escape ()
  732. X{
  733. X    char shell[LEN];
  734. X    char *p;
  735. X
  736. X#ifdef SIGTSTP
  737. X    sigtype_t (*susp)() = (sigtype_t *) 0;
  738. X#endif
  739. X
  740. X    sprintf (msg, txt_shell_escape, default_shell_command);
  741. X    
  742. X    if (! prompt_string (msg, shell))
  743. X        my_strncpy (shell, get_val ("SHELL", DEFAULT_SHELL), sizeof (shell));
  744. X
  745. X    for (p = shell; *p && (*p == ' ' || *p == '\t'); p++)
  746. X        continue;
  747. X
  748. X    if (*p) {
  749. X        my_strncpy (default_shell_command, p, sizeof (default_shell_command));
  750. X    } else {
  751. X        if (default_shell_command[0]) {
  752. X            my_strncpy (shell, default_shell_command, sizeof (shell));
  753. X        } else {
  754. X            my_strncpy (shell, get_val ("SHELL", DEFAULT_SHELL), sizeof (shell));
  755. X        }
  756. X        p = shell;
  757. X    }
  758. X
  759. X    ClearScreen ();
  760. X    sprintf (msg, "Shell Command (%s)", p);
  761. X    center_line (0, TRUE, msg);
  762. X    MoveCursor (INDEX_TOP, 0);
  763. X    
  764. X    EndWin ();
  765. X    Raw (FALSE);
  766. X
  767. X#ifdef SIGTSTP
  768. X    if (do_sigtstp)
  769. X        susp = signal (SIGTSTP, SIG_DFL);
  770. X#endif
  771. X
  772. X    system (p);
  773. X
  774. X#ifdef SIGTSTP
  775. X    if (do_sigtstp)
  776. X        signal (SIGTSTP, susp);
  777. X#endif
  778. X
  779. X    Raw (TRUE);
  780. X    InitWin ();
  781. X
  782. X    mail_setup ();
  783. X
  784. X    continue_prompt ();
  785. X
  786. X    if (draw_arrow_mark) {
  787. X        ClearScreen ();
  788. X    }
  789. X}
  790. X
  791. X
  792. Xvoid tin_done (ret)
  793. X    int ret;
  794. X{
  795. X    extern char index_file[PATH_LEN];
  796. X    char group_path[PATH_LEN], *p;
  797. X    int ask = TRUE;
  798. X    register int i, j;
  799. X    
  800. X    /*
  801. X     * check if any groups were read & ask if they should marked read
  802. X     */
  803. X    if (catchup_read_groups) {
  804. X        for (i = 0 ; i < group_top ; i++) {
  805. X            if (active[my_group[i]].attribute.read) {
  806. X                if (ask) {
  807. X                    if (prompt_yn (LINES, "Catchup all groups entered during this session? (y/n): ", 'n')) {
  808. X                        ask = FALSE;
  809. X                        thread_arts = FALSE;    /* speeds up index loading */
  810. X                    } else {
  811. X                        break;
  812. X                    }
  813. X                }
  814. X                sprintf (msg, "Catchup %s...", active[my_group[i]].name);
  815. X                wait_message (msg);
  816. X                my_strncpy (group_path, active[my_group[i]].name, sizeof (group_path));
  817. X                for (p = group_path ; *p ; p++) {
  818. X                    if (*p == '.') {
  819. X                        *p = '/';
  820. X                    }
  821. X                }
  822. X                index_group (active[my_group[i]].name, group_path);
  823. X                for (j = 0; j < top; j++) {
  824. X                    arts[j].unread = ART_READ;
  825. X                }
  826. X                update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  827. X            }
  828. X        }
  829. X    }
  830. X    nntp_close ();            /* disconnect from NNTP server */
  831. X    free_all_arrays ();        /* deallocate all arrays */
  832. X    ClearScreen ();
  833. X    EndWin ();
  834. X    Raw (FALSE);
  835. X
  836. X    if (read_news_via_nntp && xindex_supported) {
  837. X        unlink (index_file);
  838. X    }
  839. X
  840. X    exit (ret);
  841. X}
  842. X
  843. X#ifdef USE_MKDIR
  844. Xmkdir (path, mode)
  845. X    char *path;
  846. X    int mode;
  847. X{
  848. X    char buf[LEN];
  849. X    struct stat sb;
  850. X
  851. X    sprintf(buf, "mkdir %s", path);
  852. X    if (stat (path, &sb) == -1) {
  853. X        system (buf);
  854. X        chmod (path, mode);
  855. X    }
  856. X}
  857. X#endif
  858. X
  859. X/*
  860. X * hash group name for fast lookup later 
  861. X */
  862. X
  863. Xlong hash_groupname (group)
  864. X    char *group;
  865. X{
  866. X    unsigned long hash_value;
  867. X    unsigned char *ptr = (unsigned char *) group;
  868. X
  869. X    hash_value = *ptr++;
  870. X
  871. X    while (*ptr)
  872. X        hash_value = ((hash_value << 1) ^ *ptr++) % TABLE_SIZE;
  873. X
  874. X    return (hash_value);
  875. X}
  876. X
  877. X
  878. Xvoid rename_file (old_filename, new_filename)
  879. X    char *old_filename;
  880. X    char *new_filename;
  881. X{    
  882. X    char buf[LEN];
  883. X    
  884. X    unlink (new_filename);
  885. X    
  886. X    if (link (old_filename, new_filename) == -1) {
  887. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  888. X        perror_message (buf, "ONE");
  889. X        return;
  890. X    }
  891. X    if (unlink (old_filename) == -1) {
  892. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  893. X        perror_message (buf, "TWO");
  894. X        return;
  895. X    }
  896. X}
  897. X
  898. X
  899. Xchar *str_dup (str)
  900. X    char *str;
  901. X{
  902. X    char *dup = (char *) 0;
  903. X
  904. X    if (str) {
  905. X        dup = my_malloc (strlen (str)+1);
  906. X        strcpy (dup, str);
  907. X    }
  908. X    return dup;
  909. X}
  910. X
  911. X
  912. Xint invoke_cmd (nam)
  913. X    char *nam;
  914. X{
  915. X    int ret;
  916. X    int time_remaining;
  917. X    
  918. X#ifdef SIGTSTP
  919. X    sigtype_t (*susp)() = (sigtype_t *) 0;
  920. X#endif
  921. X#ifndef NO_RESYNC_ACTIVE_FILE
  922. X    time_remaining = alarm (0);    /* save time remaining on alarm clock */
  923. X#endif
  924. X
  925. X    EndWin ();
  926. X    Raw (FALSE);
  927. X
  928. X#ifdef SIGTSTP
  929. X    if (do_sigtstp)
  930. X        susp = signal(SIGTSTP, SIG_DFL);
  931. X#endif
  932. X
  933. X    ret = system (nam);
  934. X
  935. X#ifdef SIGTSTP
  936. X    if (do_sigtstp)
  937. X        signal (SIGTSTP, susp);
  938. X#endif
  939. X
  940. X    Raw (TRUE);
  941. X    InitWin ();
  942. X
  943. X#ifndef NO_RESYNC_ACTIVE_FILE
  944. X    alarm (time_remaining);    /* restart resync alarm clock */
  945. X#endif
  946. X    
  947. X    return ret == 0;
  948. X}
  949. X
  950. X
  951. Xvoid draw_percent_mark (cur_num, max_num)
  952. X    int cur_num;
  953. X    int max_num;
  954. X{
  955. X    char buf[32];
  956. X    int percent = 0;
  957. X
  958. X    if (NOTESLINES <= 0) {
  959. X        return;
  960. X    }
  961. X
  962. X    if (cur_num <= 0 && max_num <= 0) {
  963. X        return;
  964. X    }
  965. X        
  966. X    percent = cur_num * 100 / max_num;
  967. X    sprintf (buf, "%s(%d%%) [%d/%d]", txt_more, percent, cur_num, max_num);
  968. X    MoveCursor (LINES, (COLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS));
  969. X    StartInverse ();    
  970. X    fputs (buf, stdout);
  971. X    fflush (stdout);
  972. X    EndInverse ();
  973. X}
  974. X
  975. Xvoid set_real_uid_gid ()
  976. X{
  977. X    if (local_index)
  978. X        return;
  979. X
  980. X    umask (real_umask);
  981. X    
  982. X#if defined(BSD) && ! defined(sinix)
  983. X#ifdef sun
  984. X    if (seteuid (real_uid) == -1) {
  985. X        perror_message ("Error setreuid(real) failed", "");
  986. X    }
  987. X    if (setegid (real_gid) == -1) {
  988. X        perror_message ("Error setregid(real) failed", "");
  989. X    }
  990. X#else
  991. X    if (setreuid (tin_uid, real_uid) == -1) {
  992. X        perror_message ("Error setreuid(real) failed", "");
  993. X    }
  994. X    if (setregid (tin_gid, real_gid) == -1) {
  995. X        perror_message ("Error setregid(real) failed", "");
  996. X    }
  997. X#endif    /* sun */    
  998. X#else
  999. X    if (setuid (real_uid) == -1) {
  1000. X        perror_message ("Error setuid(real) failed", "");
  1001. X    }
  1002. X    if (setgid (real_gid) == -1) {
  1003. X        perror_message ("Error setgid(real) failed", "");
  1004. X    }
  1005. X#endif
  1006. X}
  1007. X
  1008. X
  1009. Xvoid set_tin_uid_gid ()
  1010. X{
  1011. X    if (local_index)
  1012. X        return;
  1013. X
  1014. X    umask (real_umask);
  1015. X    
  1016. X#if defined(BSD) && ! defined(sinix)
  1017. X#ifdef sun
  1018. X    if (seteuid (tin_uid) == -1) {
  1019. X        perror_message ("Error setreuid(real) failed", "");
  1020. X    }
  1021. X    if (setegid (tin_gid) == -1) {
  1022. X        perror_message ("Error setregid(real) failed", "");
  1023. X    }
  1024. X#else
  1025. X    if (setreuid (real_uid, tin_uid) == -1) {
  1026. X        perror_message ("Error setreuid(tin) failed", "");
  1027. X    }
  1028. X    if (setregid (real_gid, tin_gid) == -1) {
  1029. X        perror_message ("Error setregid(tin) failed", "");
  1030. X    }
  1031. X#endif    /* sun */    
  1032. X#else
  1033. X    if (setuid (tin_uid) == -1) {
  1034. X        perror_message ("Error setuid(tin) failed", "");
  1035. X    }
  1036. X    if (setgid (tin_gid) == -1) {
  1037. X        perror_message ("Error setgid(tin) failed", "");
  1038. X    }
  1039. X#endif
  1040. X}
  1041. X
  1042. X
  1043. Xvoid basename (dirname, program)
  1044. X    char *dirname;        /* argv[0] */
  1045. X    char *program;        /* progname is returned */
  1046. X{
  1047. X    int i;
  1048. X    
  1049. X    strcpy (program, dirname);
  1050. X    
  1051. X    for (i=(int) strlen (dirname)-1 ; i ; i--) {
  1052. X        if (dirname[i] == '/') {
  1053. X            strcpy (program, dirname+(i+1));
  1054. X            break;
  1055. X        }
  1056. X    }
  1057. X}
  1058. X
  1059. X
  1060. X/*
  1061. X *  Record size of mailbox so we can detect if new mail has arrived
  1062. X */
  1063. X
  1064. Xvoid mail_setup ()
  1065. X{
  1066. X    struct stat buf;
  1067. X
  1068. X    mailbox_name = get_val ("MAIL", mailbox);
  1069. X
  1070. X    if (stat (mailbox_name, &buf) >= 0) {
  1071. X        mailbox_size = buf.st_size;
  1072. X    } else {
  1073. X        mailbox_size = 0;
  1074. X    }
  1075. X}
  1076. X
  1077. X/*
  1078. X *  Return TRUE if new mail has arrived
  1079. X */
  1080. X
  1081. Xint mail_check ()
  1082. X{
  1083. X    struct stat buf;
  1084. X
  1085. X    if (mailbox_name != (char *) 0 &&
  1086. X        stat(mailbox_name, &buf) >= 0 &&
  1087. X        mailbox_size < buf.st_size) {
  1088. X        return TRUE;
  1089. X    }
  1090. X
  1091. X    return FALSE;
  1092. X}
  1093. X
  1094. X/*
  1095. X *  Parse various From: lines into the component mail addresses and
  1096. X *  real names
  1097. X */
  1098. X
  1099. Xvoid parse_from (str, addr, name)
  1100. X    char *str;
  1101. X    char *addr;
  1102. X    char *name;
  1103. X{
  1104. X    register int c;
  1105. X    register char *cp, *ncp;
  1106. X    int gotlt, lastsp, level;
  1107. X
  1108. X    gotlt = 0;
  1109. X    lastsp = 0;
  1110. X    cp = addr;
  1111. X    ncp = name;
  1112. X    while (*str == ' ')
  1113. X        ++str;
  1114. X    while (c = *str++)
  1115. X        switch (c) {
  1116. X        case '(':
  1117. X            ncp = name;
  1118. X            level = 1;
  1119. X            while (*str != '\0' && level) {
  1120. X                switch (c = *str++) {
  1121. X                    case '(':
  1122. X                        *ncp++ = c;
  1123. X                        level++;
  1124. X                        break;
  1125. X                    case ')':
  1126. X                        level--;
  1127. X                        if (level > 0)
  1128. X                            *ncp++ = c;
  1129. X                        break;
  1130. X                    default:
  1131. X                        if (c != '"') {    /* IL */
  1132. X                            *ncp++ = c;
  1133. X                        }    
  1134. X                        break;
  1135. X                }
  1136. X            }
  1137. X            if (*str)
  1138. X                str++;
  1139. X            lastsp = 0;
  1140. X            break;
  1141. X        case ' ':
  1142. X            if (str[0] == 'a' && str[1] == 't' && str[2] == ' ')
  1143. X                str += 3, *cp++ = '@';
  1144. X            else if (str[0] == '@' && str[1] == ' ')
  1145. X                str += 2, *cp++ = '@';
  1146. X            else
  1147. X                lastsp = 1;
  1148. X            if (ncp > name)
  1149. X                *ncp++ = ' ';
  1150. X            break;
  1151. X        case '<':
  1152. X            cp = addr;
  1153. X            gotlt++;
  1154. X            lastsp = 0;
  1155. X            break;
  1156. X        case '>':
  1157. X            if (gotlt)
  1158. X                goto done;
  1159. X            /* FALL THROUGH CASE */
  1160. X        default:
  1161. X            if (lastsp) {
  1162. X                lastsp = 0;
  1163. X                *cp++ = ' ';
  1164. X            }
  1165. X            *cp++ = c;
  1166. X            if (! gotlt)
  1167. X                *ncp++ = c;
  1168. X            break;
  1169. X        }
  1170. Xdone:
  1171. X    *cp = 0;
  1172. X    while (ncp>name && ncp[-1]==' ')
  1173. X        --ncp;
  1174. X    *ncp = 0;
  1175. X    if (*addr == '@') {
  1176. X        char buf [512];
  1177. X
  1178. X        strcpy (buf, addr);
  1179. X        strcpy (addr, "root");
  1180. X        strcat (addr, buf);
  1181. X    }
  1182. X}
  1183. X
  1184. X/*
  1185. X *  Convert a string to a long, only look at first n characters
  1186. X */
  1187. X
  1188. Xlong my_atol (s, n)
  1189. X    char *s;
  1190. X    int n;
  1191. X{
  1192. X    long ret = 0;
  1193. X
  1194. X    while (*s && n--) {
  1195. X        if (*s >= '0' && *s <= '9')
  1196. X            ret = ret * 10 + (*s - '0');
  1197. X        else
  1198. X            return -1;
  1199. X        s++;
  1200. X    }
  1201. X
  1202. X    return ret;
  1203. X}
  1204. X
  1205. X/*
  1206. X *  strcmp that ignores case
  1207. X */
  1208. X
  1209. X#define FOLD_TO_UPPER(a)    (islower ((int) (a)) ? toupper ((int) (a)) : (a))
  1210. X
  1211. Xint my_stricmp (p, q)
  1212. X    char *p;
  1213. X    char *q;
  1214. X{
  1215. X    for (; FOLD_TO_UPPER (*p) == FOLD_TO_UPPER (*q); ++p, ++q) {
  1216. X        if (*p == '\0') {
  1217. X            return (0);
  1218. X        }
  1219. X    }        
  1220. X
  1221. X    return (FOLD_TO_UPPER (*p) - FOLD_TO_UPPER (*q));
  1222. X}
  1223. X
  1224. X/*
  1225. X *  Return a pointer into s eliminating any leading Re:'s.  Example:
  1226. X *
  1227. X *      Re: Reorganization of misc.jobs
  1228. X *      ^   ^
  1229. X */
  1230. X
  1231. Xchar *eat_re (s)
  1232. X    char *s;
  1233. X{
  1234. X
  1235. X    while (*s == 'r' || *s == 'R') {
  1236. X        if ((*(s+1) == 'e' || *(s+1) == 'E')) {
  1237. X            if (*(s+2) == ':')
  1238. X                s += 3;
  1239. X            else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':')
  1240. X                s += 5;            /* hurray nn */
  1241. X            else
  1242. X                break;
  1243. X        } else
  1244. X            break;
  1245. X        while (*s == ' ')
  1246. X            s++;
  1247. X    }
  1248. X
  1249. X    return s;
  1250. X}
  1251. X
  1252. X/*
  1253. X *  Hash the subjects (after eating the Re's off) for a quicker
  1254. X *  thread search later.  We store the hashes for subjects in the
  1255. X *  index file for speed.
  1256. X */
  1257. X
  1258. Xlong hash_s (s)
  1259. X    char *s;
  1260. X{
  1261. X    long h = 0;
  1262. X    unsigned char *t = (unsigned char *) s;
  1263. X
  1264. X    while (*t)
  1265. X        h = h * 64 + *t++;
  1266. X
  1267. X    return h;
  1268. X}
  1269. X
  1270. X/*
  1271. X *  strncpy that stops at a newline and null terminates
  1272. X */
  1273. X
  1274. Xvoid my_strncpy (p, q, n)
  1275. X    char *p;
  1276. X    char *q;
  1277. X    int n;
  1278. X{
  1279. X    while (n--) {
  1280. X        if (! *q || *q == '\n')
  1281. X            break;
  1282. X        *p++ = *q++;
  1283. X    }
  1284. X    *p = '\0';
  1285. X}
  1286. X
  1287. X
  1288. Xint untag_all_articles ()
  1289. X{
  1290. X    int untagged = FALSE;
  1291. X    register int i;
  1292. X
  1293. X    for (i=0 ; i < top ; i++) {
  1294. X        if (arts[i].tagged) {
  1295. X            arts[i].tagged = FALSE;
  1296. X            untagged = TRUE;
  1297. X        }
  1298. X    }
  1299. X    num_of_tagged_arts = 0;
  1300. X
  1301. X    return (untagged);
  1302. X}
  1303. X
  1304. X
  1305. X/*
  1306. X * ANSI C strstr () - Uses Boyer-Moore algorithm.
  1307. X */
  1308. Xchar *str_str (text, pattern, patlen)
  1309. X    char *text;
  1310. X    char *pattern;
  1311. X    int patlen;
  1312. X{
  1313. X    register unsigned char *p, *t;
  1314. X    register int i, p1, j, *delta;
  1315. X    int deltaspace[256];
  1316. X    int textlen;
  1317. X
  1318. X    textlen = strlen (text);
  1319. X
  1320. X    /* algorithm fails if pattern is empty */
  1321. X    if ((p1 = patlen) == 0)
  1322. X        return (text);
  1323. X
  1324. X    /* code below fails (whenever i is unsigned) if pattern too long */
  1325. X    if (p1 > textlen)
  1326. X        return (NULL);
  1327. X
  1328. X    /* set up deltas */
  1329. X    delta = deltaspace;
  1330. X    for (i = 0; i <= 255; i++)
  1331. X        delta[i] = p1;
  1332. X    for (p = (unsigned char *) pattern, i = p1; --i > 0;)
  1333. X        delta[*p++] = i;
  1334. X
  1335. X    /*
  1336. X     * From now on, we want patlen - 1.
  1337. X     * In the loop below, p points to the end of the pattern,
  1338. X     * t points to the end of the text to be tested against the
  1339. X     * pattern, and i counts the amount of text remaining, not
  1340. X     * including the part to be tested.
  1341. X     */
  1342. X    p1--;
  1343. X    p = (unsigned char *) pattern + p1;
  1344. X    t = (unsigned char *) text + p1;
  1345. X    i = textlen - patlen;
  1346. X    for (;;) {
  1347. X        if (*p == *t && memcmp ((p - p1), (t - p1), p1) == 0)
  1348. X            return ((char *)t - p1);
  1349. X        j = delta[*t];
  1350. X        if (i < j)
  1351. X            break;
  1352. X        i -= j;
  1353. X        t += j;
  1354. X    }
  1355. X    return (NULL);
  1356. X}
  1357. X
  1358. X
  1359. X
  1360. Xvoid get_author (thread, respnum, str)
  1361. X    int thread;
  1362. X    int respnum;
  1363. X    char *str;
  1364. X{    
  1365. X    extern int threaded_on_subject;
  1366. X    int author;
  1367. X/*
  1368. X    int len_from = max_from;
  1369. X
  1370. X    if (thread) {
  1371. X        if (threaded_on_subject) {
  1372. X            len_from = max_subj+max_from;
  1373. X        } else {
  1374. X            len_from = max_from;
  1375. X        }
  1376. X        author = SHOW_FROM_BOTH;
  1377. X    } else {
  1378. X        author = show_author;
  1379. X    } 
  1380. X*/
  1381. X    if (thread) {
  1382. X        if (threaded_on_subject) {
  1383. X            author = SHOW_FROM_BOTH;
  1384. X        } else {
  1385. X            author = show_author;
  1386. X        }
  1387. X    } else {
  1388. X        author = show_author;
  1389. X    } 
  1390. X    
  1391. X    switch (author) { 
  1392. X        case SHOW_FROM_NONE:
  1393. X            str[0] = '\0';
  1394. X            break;
  1395. X        case SHOW_FROM_ADDR:
  1396. X            strcpy (str, arts[respnum].from);
  1397. X            break;
  1398. X        case SHOW_FROM_NAME:
  1399. X            strcpy (str, arts[respnum].name);
  1400. X            break;
  1401. X        case SHOW_FROM_BOTH:
  1402. X            if (arts[respnum].name != arts[respnum].from) { 
  1403. X                sprintf (str, "%s (%s)", arts[respnum].name, arts[respnum].from);
  1404. X            } else { 
  1405. X                strcpy (str, arts[respnum].from);
  1406. X            }
  1407. X            break;
  1408. X    }
  1409. X}
  1410. X
  1411. X
  1412. Xvoid toggle_inverse_video ()
  1413. X{
  1414. X    inverse_okay = !inverse_okay;
  1415. X    if (inverse_okay) {
  1416. X#ifndef USE_INVERSE_HACK    
  1417. X        draw_arrow_mark = FALSE;
  1418. X#endif        
  1419. X        info_message (txt_inverse_on);
  1420. X    } else {
  1421. X        draw_arrow_mark = TRUE;
  1422. X        info_message (txt_inverse_off);
  1423. X    }
  1424. X}
  1425. X
  1426. X
  1427. Xint get_arrow_key ()
  1428. X{
  1429. X    int ch;
  1430. X    
  1431. X    ch = ReadCh ();
  1432. X    if (ch == '[' || ch == 'O')
  1433. X        ch = ReadCh();
  1434. X    switch (ch) {
  1435. X        case 'A':
  1436. X        case 'D':
  1437. X        case 'i':
  1438. X            return KEYMAP_UP;
  1439. X
  1440. X        case 'B':
  1441. X        case 'C':
  1442. X            return KEYMAP_DOWN;
  1443. X
  1444. X        case 'I':        /* ansi  PgUp */
  1445. X        case 'V':        /* at386 PgUp */
  1446. X        case 'S':        /* 97801 PgUp */
  1447. X        case 'v':        /* emacs style */
  1448. X            return KEYMAP_PAGE_UP;
  1449. X
  1450. X        case 'G':        /* ansi  PgDn */
  1451. X        case 'U':        /* at386 PgDn */
  1452. X        case 'T':        /* 97801 PgDn */
  1453. X            return KEYMAP_PAGE_DOWN;
  1454. X
  1455. X        case 'H':        /* at386  Home */
  1456. X            return KEYMAP_HOME;
  1457. X                    
  1458. X        case 'F':        /* ansi   End */
  1459. X        case 'Y':        /* at386  End */
  1460. X            return KEYMAP_END;
  1461. X
  1462. X        case '5':        /* vt200 PgUp */
  1463. X            ch = ReadCh ();    /* eat the ~  */
  1464. X            return KEYMAP_PAGE_UP;
  1465. X
  1466. X        case '6':        /* vt200 PgUp */
  1467. X            ch = ReadCh ();    /* eat the ~  */
  1468. X            return KEYMAP_PAGE_DOWN;
  1469. X
  1470. X        case '1':        /* vt200 PgUp */
  1471. X            ch = ReadCh ();    /* eat the ~  */
  1472. X            return KEYMAP_HOME;
  1473. X                    
  1474. X        case '4':        /* vt200 PgUp */
  1475. X            ch = ReadCh ();    /* eat the ~  */
  1476. X            return KEYMAP_END;
  1477. X
  1478. X        default:
  1479. X            return KEYMAP_UNKNOWN;
  1480. X    }
  1481. X}
  1482. END_OF_FILE
  1483.   if test 15398 -ne `wc -c <'misc.c'`; then
  1484.     echo shar: \"'misc.c'\" unpacked with wrong size!
  1485.   fi
  1486.   # end of 'misc.c'
  1487. fi
  1488. if test -f 'nntplib.c' -a "${1}" != "-c" ; then 
  1489.   echo shar: Will not clobber existing file \"'nntplib.c'\"
  1490. else
  1491.   echo shar: Extracting \"'nntplib.c'\" \(14882 characters\)
  1492.   sed "s/^X//" >'nntplib.c' <<'END_OF_FILE'
  1493. X/*
  1494. X *  Project   : tin - a threaded Netnews reader
  1495. X *  Module    : nntplib.c
  1496. X *  Author    : S.Barber & I.Lea
  1497. X *  Created   : 12-01-91
  1498. X *  Updated   : 06-05-92
  1499. X *  Notes     : NNTP client routines taken from clientlib.c v1.6
  1500. X *              1.5.11 (10 February 1991)
  1501. X *  Copyright : (c) Copyright 1991-92 by Stan Barber & Iain Lea
  1502. X *              Permission is hereby granted to copy, reproduce, redistribute
  1503. X *              or otherwise use this software  as long as: there is no
  1504. X *              monetary  profit  gained  specifically  from the use or
  1505. X *              reproduction or this software, it is not  sold, rented,
  1506. X *              traded or otherwise marketed, and this copyright notice
  1507. X *              is included prominently in any copy made. 
  1508. X */
  1509. X
  1510. X#ifdef NNTP_ONLY
  1511. X#    define    NNTP_ABLE
  1512. X#endif
  1513. X
  1514. X#include <stdio.h>
  1515. X
  1516. X#ifndef CDROM_ABLE
  1517. X
  1518. XFILE    *ser_rd_fp = NULL;
  1519. XFILE    *ser_wr_fp = NULL;
  1520. X
  1521. X#ifdef NNTP_ABLE
  1522. X#    ifdef apollo
  1523. X#        include </bsd4.3/usr/include/sys/types.h>
  1524. X#    else
  1525. X#        include <sys/types.h>
  1526. X#    endif
  1527. X#    include <ctype.h>
  1528. X#    ifdef TLI
  1529. X#        include    <fcntl.h>
  1530. X#        include    <tiuser.h>
  1531. X#        include    <stropts.h>
  1532. X#        include    <sys/socket.h>
  1533. X#        ifdef WIN_TCP
  1534. X#            include    <sys/in.h>
  1535. X#        else
  1536. X#            include    <netinet/in.h>
  1537. X#        endif
  1538. X#        define    IPPORT_NNTP    ((unsigned short) 119)
  1539. X#        include     <netdb.h>    /* All TLI implementations may not have this */
  1540. X#    else
  1541. X#        ifdef apollo
  1542. X#            include </bsd4.3/usr/include/sys/socket.h>
  1543. X#            include </bsd4.3/usr/include/netinet/in.h>
  1544. X#            include </bsd4.3/usr/include/netdb.h>
  1545. X#        else
  1546. X#            include <sys/socket.h>
  1547. X#            include <netinet/in.h>
  1548. X#            ifndef EXCELAN
  1549. X#                include <netdb.h>
  1550. X#            endif
  1551. X#        endif
  1552. X#    endif /* !TLI */
  1553. X
  1554. X#    ifndef BSD
  1555. X#        define    index(a,b)    strchr(a,b)
  1556. X#        define    bcopy(a,b,c)    memcpy(b,a,c)
  1557. X#        define    bzero(a,b)    memset(a,'\0',b)
  1558. X#    endif
  1559. X
  1560. X#    ifdef EXCELAN
  1561. X#        define    IPPORT_NNTP    ((unsigned short) 119)
  1562. X#        if __STDC__
  1563. X            int connect (int, struct sockaddr *);
  1564. X            unsigned short htons (unsigned short);
  1565. X            unsigned long rhost (char **);
  1566. X            int rresvport (int);
  1567. X            int socket (int, struct sockproto *, struct sockaddr_in *, int);
  1568. X#        endif
  1569. X#    endif
  1570. X
  1571. X#    ifdef DECNET
  1572. X#        include <netdnet/dn.h>
  1573. X#        include <netdnet/dnetdb.h>
  1574. X#    endif
  1575. X
  1576. X#    include "nntplib.h"
  1577. X
  1578. X
  1579. X#endif /* NNTP_ABLE */
  1580. X
  1581. X/*
  1582. X * getserverbyfile    Get the name of a server from a named file.
  1583. X *            Handle white space and comments.
  1584. X *            Use NNTPSERVER environment variable if set.
  1585. X *
  1586. X *    Parameters:    "file" is the name of the file to read.
  1587. X *
  1588. X *    Returns:    Pointer to static data area containing the
  1589. X *            first non-ws/comment line in the file.
  1590. X *            NULL on error (or lack of entry in file).
  1591. X *
  1592. X *    Side effects:    None.
  1593. X */
  1594. X
  1595. Xchar *getserverbyfile (file)
  1596. X    char    *file;
  1597. X{
  1598. X#ifdef NNTP_ABLE
  1599. X    extern int debug;
  1600. X    register FILE    *fp;
  1601. X    register char    *cp;
  1602. X    static char    buf[256];
  1603. X
  1604. X    if (debug == 1) {
  1605. X        wait_message ("USING BUILTIN NNTP");
  1606. X    }
  1607. X    
  1608. X    if (cp = (char *) getenv ("NNTPSERVER")) {
  1609. X        (void) strcpy (buf, cp);
  1610. X        return (buf);
  1611. X    }
  1612. X
  1613. X    if (file == NULL)
  1614. X        return (NULL);
  1615. X
  1616. X    if ((fp = fopen (file, "r")) == NULL)
  1617. X        return (NULL);
  1618. X
  1619. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  1620. X        if (*buf == '\n' || *buf == '#') {
  1621. X            continue;
  1622. X        }
  1623. X        cp = (char *) index(buf, '\n');
  1624. X        if (cp) {
  1625. X            *cp = '\0';
  1626. X        }
  1627. X        (void) fclose (fp);
  1628. X        return (buf);
  1629. X    }
  1630. X
  1631. X    (void) fclose (fp);
  1632. X#endif /* NNTP_ABLE */
  1633. X    return (NULL);             /* No entry */
  1634. X}
  1635. X
  1636. X/*
  1637. X * server_init  Get a connection to the remote news server.
  1638. X *
  1639. X *    Parameters:    "machine" is the machine to connect to.
  1640. X *
  1641. X *    Returns:    -1 on error
  1642. X *            server's initial response code on success.
  1643. X *
  1644. X *    Side effects:    Connects to server.
  1645. X *            "ser_rd_fp" and "ser_wr_fp" are fp's
  1646. X *            for reading and writing to server.
  1647. X */
  1648. X
  1649. Xint server_init (machine)
  1650. X    char    *machine;
  1651. X{
  1652. X#ifdef NNTP_ABLE
  1653. X    int    sockt_rd, sockt_wr;
  1654. X    char    line[256];
  1655. X#ifdef DECNET
  1656. X    char    *cp;
  1657. X
  1658. X    cp = (char *) index(machine, ':');
  1659. X
  1660. X    if (cp && cp[1] == ':') {
  1661. X        *cp = '\0';
  1662. X        sockt_rd = get_dnet_socket (machine);
  1663. X    } else {
  1664. X        sockt_rd = get_tcp_socket (machine);
  1665. X    }
  1666. X#else
  1667. X    sockt_rd = get_tcp_socket (machine);
  1668. X#endif
  1669. X
  1670. X    if (sockt_rd < 0)
  1671. X        return (-1);
  1672. X
  1673. X    /*
  1674. X     * Now we'll make file pointers (i.e., buffered I/O) out of
  1675. X     * the socket file descriptor.  Note that we can't just
  1676. X     * open a fp for reading and writing -- we have to open
  1677. X     * up two separate fp's, one for reading, one for writing.
  1678. X     */
  1679. X
  1680. X    if ((ser_rd_fp = (FILE *) fdopen (sockt_rd, "r")) == NULL) {
  1681. X        perror ("server_init: fdopen #1");
  1682. X        return (-1);
  1683. X    }
  1684. X
  1685. X    sockt_wr = dup (sockt_rd);
  1686. X#ifdef TLI
  1687. X    if (t_sync (sockt_rd) < 0) {    /* Sync up new fd with TLI */
  1688. X            t_error ("server_init: t_sync");
  1689. X        ser_rd_fp = NULL;        /* from above */
  1690. X        return (-1);
  1691. X    }
  1692. X#endif
  1693. X    if ((ser_wr_fp = (FILE *) fdopen (sockt_wr, "w")) == NULL) {
  1694. X        perror ("server_init: fdopen #2");
  1695. X        ser_rd_fp = NULL;        /* from above */
  1696. X        return (-1);
  1697. X    }
  1698. X
  1699. X    /*
  1700. X     * Now get the server's signon message
  1701. X     */
  1702. X
  1703. X    (void) get_server (line, sizeof (line));
  1704. X    return (atoi (line));
  1705. X#else
  1706. X    return (-1);
  1707. X#endif /* NNTP_ABLE */
  1708. X}
  1709. X
  1710. X/*
  1711. X * get_tcp_socket -- get us a socket connected to the news server.
  1712. X *
  1713. X *    Parameters:    "machine" is the machine the server is running on.
  1714. X *
  1715. X *    Returns:    Socket connected to the news server if
  1716. X *            all is ok, else -1 on error.
  1717. X *
  1718. X *    Side effects:    Connects to server.
  1719. X *
  1720. X *    Errors:        Printed via perror.
  1721. X */
  1722. X
  1723. Xint get_tcp_socket (machine)
  1724. X    char    *machine;    /* remote host */
  1725. X{
  1726. X#ifdef NNTP_ABLE
  1727. X    int    s = -1;
  1728. X    struct    sockaddr_in sin;
  1729. X#ifdef TLI 
  1730. X    struct    hostent *gethostbyname (), *hp;
  1731. X    struct    t_call    *callptr;
  1732. X
  1733. X    /*
  1734. X     * Create a TCP transport endpoint.
  1735. X     */
  1736. X    if ((s = t_open ("/dev/tcp", O_RDWR, (struct t_info*) 0)) < 0){
  1737. X        t_error ("t_open: can't t_open /dev/tcp");
  1738. X        return (-1);
  1739. X    }
  1740. X    if (t_bind (s, (struct t_bind *) 0, (struct t_bind *) 0) < 0) {
  1741. X           t_error ("t_bind");
  1742. X        t_close (s);
  1743. X        return (-1);
  1744. X    }
  1745. X    bzero((char *) &sin, sizeof (sin));    
  1746. X    sin.sin_family = AF_INET;
  1747. X    sin.sin_port = htons (IPPORT_NNTP);
  1748. X    if (!isdigit(*machine) ||
  1749. X        (long)(sin.sin_addr.s_addr = inet_addr (machine)) == -1) {
  1750. X        if((hp = gethostbyname (machine)) == NULL) {
  1751. X            fprintf (stderr, "gethostbyname: %s: host unknown\n", machine);
  1752. X            t_close (s);
  1753. X            return (-1);
  1754. X        }
  1755. X        bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  1756. X    }
  1757. X    
  1758. X    /*
  1759. X     * Allocate a t_call structure and initialize it.
  1760. X     * Let t_alloc() initialize the addr structure of the t_call structure.
  1761. X     */
  1762. X    if ((callptr = (struct t_call *) t_alloc (s,T_CALL,T_ADDR)) == NULL){
  1763. X        t_error ("t_alloc");
  1764. X        t_close (s);
  1765. X        return (-1);
  1766. X    }
  1767. X
  1768. X    callptr->addr.maxlen = sizeof (sin);
  1769. X    callptr->addr.len = sizeof (sin);
  1770. X    callptr->addr.buf = (char *) &sin;
  1771. X    callptr->opt.len = 0;            /* no options */
  1772. X    callptr->udata.len = 0;            /* no user data with connect */
  1773. X
  1774. X    /*
  1775. X     * Connect to the server.
  1776. X     */
  1777. X    if (t_connect (s, callptr, (struct t_call *) 0) < 0) {
  1778. X        t_error ("t_connect");
  1779. X        t_close (s);
  1780. X        return (-1);
  1781. X    }
  1782. X
  1783. X    /*
  1784. X     * Now replace the timod module with the tirdwr module so that
  1785. X     * standard read() and write() system calls can be used on the
  1786. X     * descriptor.
  1787. X     */
  1788. X
  1789. X    if (ioctl (s,  I_POP,  (char *) 0) < 0) {
  1790. X        perror ("I_POP(timod)");
  1791. X        t_close (s);
  1792. X        return (-1);
  1793. X    }
  1794. X
  1795. X    if (ioctl (s,  I_PUSH, "tirdwr") < 0) {
  1796. X        perror ("I_PUSH(tirdwr)");
  1797. X        t_close (s);
  1798. X        return (-1);
  1799. X    }
  1800. X    
  1801. X#else /* !TLI */
  1802. X#ifndef EXCELAN
  1803. X    struct    servent *getservbyname(), *sp;
  1804. X    struct    hostent *gethostbyname(), *hp;
  1805. X#ifdef h_addr
  1806. X    int    x = 0;
  1807. X    register char **cp;
  1808. X    static char *alist[1];
  1809. X#endif /* h_addr */
  1810. X    unsigned long inet_addr();
  1811. X    static struct hostent def;
  1812. X    static struct in_addr defaddr;
  1813. X    static char namebuf[256];
  1814. X
  1815. X    if ((sp = getservbyname ("nntp", "tcp")) ==  NULL) {
  1816. X        fprintf (stderr, "nntp/tcp: Unknown service.\n");
  1817. X        return (-1);
  1818. X    }
  1819. X    /* If not a raw ip address, try nameserver */
  1820. X    if (!isdigit(*machine) ||
  1821. X        (long)(defaddr.s_addr = inet_addr (machine)) == -1)
  1822. X        hp = gethostbyname (machine);
  1823. X    else {
  1824. X        /* Raw ip address, fake  */
  1825. X        (void) strcpy (namebuf, machine);
  1826. X        def.h_name = namebuf;
  1827. X#ifdef h_addr
  1828. X        def.h_addr_list = alist;
  1829. X#endif
  1830. X        def.h_addr = (char *) &defaddr;
  1831. X        def.h_length = sizeof (struct in_addr);
  1832. X        def.h_addrtype = AF_INET;
  1833. X        def.h_aliases = 0;
  1834. X        hp = &def;
  1835. X    }
  1836. X    if (hp == NULL) {
  1837. X        fprintf (stderr, "%s: Unknown host.\n", machine);
  1838. X        return (-1);
  1839. X    }
  1840. X
  1841. X    bzero((char *) &sin, sizeof (sin));
  1842. X    sin.sin_family = hp->h_addrtype;
  1843. X    sin.sin_port = sp->s_port;
  1844. X#else /* EXCELAN */
  1845. X    bzero((char *) &sin, sizeof (sin));
  1846. X    sin.sin_family = AF_INET;
  1847. X#endif /* EXCELAN */
  1848. X
  1849. X    /*
  1850. X     * The following is kinda gross.  The name server under 4.3
  1851. X     * returns a list of addresses, each of which should be tried
  1852. X     * in turn if the previous one fails.  However, 4.2 hostent
  1853. X     * structure doesn't have this list of addresses.
  1854. X     * Under 4.3, h_addr is a #define to h_addr_list[0].
  1855. X     * We use this to figure out whether to include the NS specific
  1856. X     * code...
  1857. X     */
  1858. X
  1859. X#ifdef h_addr
  1860. X    /*
  1861. X     * get a socket and initiate connection -- use multiple addresses
  1862. X     */
  1863. X
  1864. X    for (cp = hp->h_addr_list; cp && *cp; cp++) {
  1865. X        s = socket (hp->h_addrtype, SOCK_STREAM, 0);
  1866. X        if (s < 0) {
  1867. X            perror ("socket");
  1868. X            return (-1);
  1869. X        }
  1870. X        bcopy(*cp, (char *) &sin.sin_addr, hp->h_length);
  1871. X        
  1872. X        if (x < 0) {
  1873. X            fprintf (stderr, "trying %s\n", (char *) inet_ntoa (sin.sin_addr));
  1874. X        }
  1875. X        x = connect (s, (struct sockaddr *) &sin, sizeof (sin));
  1876. X        if (x == 0) {
  1877. X            break;
  1878. X        }
  1879. X        fprintf (stderr, "connection to %s: ", (char *) inet_ntoa (sin.sin_addr));
  1880. X        perror ("");
  1881. X        (void) close (s);
  1882. X    }
  1883. X    if (x < 0) {
  1884. X        fprintf (stderr, "giving up...\n");
  1885. X        return (-1);
  1886. X    }
  1887. X#else    /* no name server */
  1888. X#ifdef EXCELAN
  1889. X    if ((s = socket (SOCK_STREAM,(struct sockproto *)NULL,&sin,SO_KEEPALIVE)) < 0) {
  1890. X        /* Get the socket */
  1891. X        perror ("socket");
  1892. X        return (-1);
  1893. X    }
  1894. X    bzero((char *) &sin, sizeof (sin));
  1895. X    sin.sin_family = AF_INET;
  1896. X    sin.sin_port = htons (IPPORT_NNTP);
  1897. X    /* set up addr for the connect */
  1898. X
  1899. X    if ((sin.sin_addr.s_addr = rhost (&machine)) == -1) {
  1900. X        fprintf (stderr, "%s: Unknown host.\n", machine);
  1901. X        return (-1);
  1902. X    }
  1903. X    /* And then connect */
  1904. X
  1905. X    if (connect (s, (struct sockaddr *)&sin) < 0) {
  1906. X        perror ("connect");
  1907. X        (void) close (s);
  1908. X        return (-1);
  1909. X    }
  1910. X#else /* not EXCELAN */
  1911. X    if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  1912. X        perror ("socket");
  1913. X        return (-1);
  1914. X    }
  1915. X
  1916. X    /* And then connect */
  1917. X
  1918. X    bcopy (hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  1919. X    if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
  1920. X        perror ("connect");
  1921. X        (void) close (s);
  1922. X        return (-1);
  1923. X    }
  1924. X
  1925. X#endif /* !EXCELAN */
  1926. X#endif /* !h_addr */
  1927. X#endif /* !TLI */
  1928. X    return (s);
  1929. X#else
  1930. X    return (-1);
  1931. X#endif /* NNTP_ABLE */
  1932. X}
  1933. X
  1934. X#ifdef DECNET
  1935. X/*
  1936. X * get_dnet_socket -- get us a socket connected to the news server.
  1937. X *
  1938. X *    Parameters:    "machine" is the machine the server is running on.
  1939. X *
  1940. X *    Returns:    Socket connected to the news server if
  1941. X *            all is ok, else -1 on error.
  1942. X *
  1943. X *    Side effects:    Connects to server.
  1944. X *
  1945. X *    Errors:        Printed via nerror.
  1946. X */
  1947. X
  1948. Xint get_dnet_socket (machine)
  1949. X    char    *machine;
  1950. X{
  1951. X#ifdef NNTP_ABLE
  1952. X    int    s, area, node;
  1953. X    struct    sockaddr_dn sdn;
  1954. X    struct    nodeent *getnodebyname(), *np;
  1955. X
  1956. X    bzero((char *) &sdn, sizeof (sdn));
  1957. X
  1958. X    switch (s = sscanf (machine, "%d%*[.]%d", &area, &node)) {
  1959. X        case 1: 
  1960. X            node = area;
  1961. X            area = 0;
  1962. X        case 2: 
  1963. X            node += area*1024;
  1964. X            sdn.sdn_add.a_len = 2;
  1965. X            sdn.sdn_family = AF_DECnet;
  1966. X            sdn.sdn_add.a_addr[0] = node % 256;
  1967. X            sdn.sdn_add.a_addr[1] = node / 256;
  1968. X            break;
  1969. X        default:
  1970. X            if ((np = getnodebyname (machine)) == NULL) {
  1971. X                fprintf (stderr, "%s: Unknown host.\n", machine);
  1972. X                return (-1);
  1973. X            } else {
  1974. X                bcopy(np->n_addr, (char *) sdn.sdn_add.a_addr, np->n_length);
  1975. X                sdn.sdn_add.a_len = np->n_length;
  1976. X                sdn.sdn_family = np->n_addrtype;
  1977. X            }
  1978. X            break;
  1979. X    }
  1980. X    sdn.sdn_objnum = 0;
  1981. X    sdn.sdn_flags = 0;
  1982. X    sdn.sdn_objnamel = strlen ("NNTP");
  1983. X    bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  1984. X
  1985. X    if ((s = socket (AF_DECnet, SOCK_STREAM, 0)) < 0) {
  1986. X        nerror ("socket");
  1987. X        return (-1);
  1988. X    }
  1989. X
  1990. X    /* And then connect */
  1991. X
  1992. X    if (connect (s, (struct sockaddr *) &sdn, sizeof (sdn)) < 0) {
  1993. X        nerror ("connect");
  1994. X        close (s);
  1995. X        return (-1);
  1996. X    }
  1997. X
  1998. X    return (s);
  1999. X#else
  2000. X    return (-1);
  2001. X#endif /* NNTP_ABLE */
  2002. X}
  2003. X#endif
  2004. X
  2005. X/*
  2006. X * handle_server_response
  2007. X *
  2008. X *    Print some informative messages based on the server's initial
  2009. X *    response code.  This is here so inews, rn, etc. can share
  2010. X *    the code.
  2011. X *
  2012. X *    Parameters:    "response" is the response code which the
  2013. X *            server sent us, presumably from "server_init",
  2014. X *            above.
  2015. X *            "nntpserver" is the news server we got the
  2016. X *            response code from.
  2017. X *
  2018. X *    Returns:    -1 if the error is fatal (and we should exit).
  2019. X *            0 otherwise.
  2020. X *
  2021. X *    Side effects:    None.
  2022. X */
  2023. X
  2024. Xint handle_server_response (response, nntpserver)
  2025. X    int    response;
  2026. X    char    *nntpserver;
  2027. X{
  2028. X#ifdef NNTP_ABLE
  2029. X    switch (response) {
  2030. X        case OK_NOPOST:        /* fall through */
  2031. X                printf ("NOTE: This machine does not have permission to post articles.\n");
  2032. X            printf ("      Please don't waste your time trying.\n\n");
  2033. X
  2034. X        case OK_CANPOST:
  2035. X            return (0);
  2036. X            break;
  2037. X
  2038. X        case ERR_ACCESS:
  2039. X            printf ("This machine does not have permission to use the %s news server.\n", nntpserver);
  2040. X            return (-1);
  2041. X            break;
  2042. X
  2043. X        default:
  2044. X            printf ("Unexpected response code from %s news server: %d\n",
  2045. X                nntpserver, response);
  2046. X            return (-1);
  2047. X            break;
  2048. X    }
  2049. X    /*NOTREACHED*/
  2050. X#else
  2051. X    return (-1);
  2052. X#endif /* NNTP_ABLE */
  2053. X}
  2054. X
  2055. X/*
  2056. X * put_server -- send a line of text to the server, terminating it
  2057. X * with CR and LF, as per ARPA standard.
  2058. X *
  2059. X *    Parameters:    "string" is the string to be sent to the
  2060. X *            server.
  2061. X *
  2062. X *    Returns:    Nothing.
  2063. X *
  2064. X *    Side effects:    Talks to the server.
  2065. X *
  2066. X *    Note:    This routine flushes the buffer each time
  2067. X *            it is called.  For large transmissions
  2068. X *            (i.e., posting news) don't use it.  Instead,
  2069. X *            do the fprintf's yourself, and then a final
  2070. X *            fflush.
  2071. X */
  2072. X
  2073. Xvoid put_server (string)
  2074. X    char *string;
  2075. X{
  2076. X#ifdef NNTP_ABLE
  2077. X    fprintf (ser_wr_fp, "%s\r\n", string);
  2078. X    (void) fflush (ser_wr_fp);
  2079. X#endif /* NNTP_ABLE */
  2080. X}
  2081. X
  2082. X/*
  2083. X * get_server -- get a line of text from the server.  Strips
  2084. X * CR's and LF's.
  2085. X *
  2086. X *    Parameters:    "string" has the buffer space for the
  2087. X *            line received.
  2088. X *            "size" is the size of the buffer.
  2089. X *
  2090. X *    Returns:    -1 on error, 0 otherwise.
  2091. X *
  2092. X *    Side effects:    Talks to server, changes contents of "string".
  2093. X */
  2094. X
  2095. Xint get_server (string, size)
  2096. X    char    *string;
  2097. X    int    size;
  2098. X{
  2099. X#ifdef NNTP_ABLE
  2100. X    register char *cp;
  2101. X
  2102. X    if (fgets (string, size, ser_rd_fp) == NULL) {
  2103. X        return (-1);
  2104. X    }
  2105. X
  2106. X    if ((cp = (char *) index(string, '\r')) != NULL) {
  2107. X        *cp = '\0';
  2108. X    } else if ((cp = (char *) index(string, '\n')) != NULL) {
  2109. X        *cp = '\0';
  2110. X    }
  2111. X
  2112. X    return (0);
  2113. X#else
  2114. X    return (-1);
  2115. X#endif /* NNTP_ABLE */
  2116. X}
  2117. X
  2118. X/*
  2119. X * close_server -- close the connection to the server, after sending
  2120. X *        the "quit" command.
  2121. X *
  2122. X *    Parameters:    None.
  2123. X *
  2124. X *    Returns:    Nothing.
  2125. X *
  2126. X *    Side effects:    Closes the connection with the server.
  2127. X *            You can't use "put_server" or "get_server"
  2128. X *            after this routine is called.
  2129. X */
  2130. X
  2131. Xvoid close_server ()
  2132. X{
  2133. X#ifdef NNTP_ABLE
  2134. X    char    ser_line[256];
  2135. X
  2136. X    if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  2137. X        return;
  2138. X
  2139. X    put_server ("QUIT");
  2140. X    (void) get_server (ser_line, sizeof (ser_line));
  2141. X
  2142. X    (void) fclose (ser_wr_fp);
  2143. X    (void) fclose (ser_rd_fp);
  2144. X#endif /* NNTP_ABLE */
  2145. X}
  2146. X
  2147. X#endif /* CDROM_ABLE */
  2148. X
  2149. END_OF_FILE
  2150.   if test 14882 -ne `wc -c <'nntplib.c'`; then
  2151.     echo shar: \"'nntplib.c'\" unpacked with wrong size!
  2152.   fi
  2153.   # end of 'nntplib.c'
  2154. fi
  2155. if test -f 'wildmat.c' -a "${1}" != "-c" ; then 
  2156.   echo shar: Will not clobber existing file \"'wildmat.c'\"
  2157. else
  2158.   echo shar: Extracting \"'wildmat.c'\" \(4798 characters\)
  2159.   sed "s/^X//" >'wildmat.c' <<'END_OF_FILE'
  2160. X/*  $Revision: 1.5 $
  2161. X**
  2162. X**  Do shell-style pattern matching for ?, \, [], and * characters.
  2163. X**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  2164. X**  could cause a segmentation violation.  It is 8bit clean.
  2165. X**
  2166. X**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  2167. X**  Rich $alz is now <rsalz@bbn.com>.
  2168. X**  April, 1991:  Replaced mutually-recursive calls with in-line code
  2169. X**  for the star character.
  2170. X**
  2171. X**  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
  2172. X**  This can greatly speed up failing wildcard patterns.  For example:
  2173. X**    pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
  2174. X**    text 1:     -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
  2175. X**    text 2:     -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
  2176. X**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
  2177. X**  the ABORT, then it takes 22310 calls to fail.  Ugh.  The following
  2178. X**  explanation is from Lars:
  2179. X**  The precondition that must be fulfilled is that DoMatch will consume
  2180. X**  at least one character in text.  This is true if *p is neither '*' nor
  2181. X**  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
  2182. X**  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
  2183. X**  FALSE, each star-loop has to run to the end of the text; with ABORT
  2184. X**  only the last one does.
  2185. X**
  2186. X**  Once the control of one instance of DoMatch enters the star-loop, that
  2187. X**  instance will return either TRUE or ABORT, and any calling instance
  2188. X**  will therefore return immediately after (without calling recursively
  2189. X**  again).  In effect, only one star-loop is ever active.  It would be
  2190. X**  possible to modify the code to maintain this context explicitly,
  2191. X**  eliminating all recursive calls at the cost of some complication and
  2192. X**  loss of clarity (and the ABORT stuff seems to be unclear enough by
  2193. X**  itself).  I think it would be unwise to try to get this into a
  2194. X**  released version unless you have a good test data base to try it out
  2195. X**  on.
  2196. X*/
  2197. X
  2198. X#define TRUE            1
  2199. X#define FALSE            0
  2200. X#define ABORT            -1
  2201. X
  2202. X
  2203. X    /* What character marks an inverted character class? */
  2204. X#define NEGATE_CLASS        '^'
  2205. X    /* Is "*" a common pattern? */
  2206. X#define OPTIMIZE_JUST_STAR
  2207. X    /* Do tar(1) matching rules, which ignore a trailing slash? */
  2208. X#undef MATCH_TAR_PATTERN
  2209. X
  2210. X
  2211. X/*
  2212. X**  Match text and p, return TRUE, FALSE, or ABORT.
  2213. X*/
  2214. Xstatic int
  2215. XDoMatch(text, p)
  2216. X    register char    *text;
  2217. X    register char    *p;
  2218. X{
  2219. X#ifndef INDEX_DAEMON
  2220. X
  2221. X    register int    last;
  2222. X    register int    matched;
  2223. X    register int    reverse;
  2224. X
  2225. X    for ( ; *p; text++, p++) {
  2226. X    if (*text == '\0' && *p != '*')
  2227. X        return ABORT;
  2228. X    switch (*p) {
  2229. X    case '\\':
  2230. X        /* Literal match with following character. */
  2231. X        p++;
  2232. X        /* FALLTHROUGH */
  2233. X    default:
  2234. X        if (*text != *p)
  2235. X        return FALSE;
  2236. X        continue;
  2237. X    case '?':
  2238. X        /* Match anything. */
  2239. X        continue;
  2240. X    case '*':
  2241. X        while (*++p == '*')
  2242. X        /* Consecutive stars act just like one. */
  2243. X        continue;
  2244. X        if (*p == '\0')
  2245. X        /* Trailing star matches everything. */
  2246. X        return TRUE;
  2247. X        while (*text)
  2248. X        if ((matched = DoMatch(text++, p)) != FALSE)
  2249. X            return matched;
  2250. X        return ABORT;
  2251. X    case '[':
  2252. X        reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  2253. X        if (reverse)
  2254. X        /* Inverted character class. */
  2255. X        p++;
  2256. X        matched = FALSE;
  2257. X        if (p[1] == ']' || p[1] == '-')
  2258. X        if (*++p == *text)
  2259. X            matched = TRUE;
  2260. X        for (last = *p; *++p && *p != ']'; last = *p)
  2261. X        /* This next line requires a good C compiler. */
  2262. X        if (*p == '-' && p[1] != ']'
  2263. X            ? *text <= *++p && *text >= last : *text == *p)
  2264. X            matched = TRUE;
  2265. X        if (matched == reverse)
  2266. X        return FALSE;
  2267. X        continue;
  2268. X    }
  2269. X    }
  2270. X
  2271. X#ifdef    MATCH_TAR_PATTERN
  2272. X    if (*text == '/')
  2273. X    return TRUE;
  2274. X#endif    /* MATCH_TAR_ATTERN */
  2275. X    return *text == '\0';
  2276. X
  2277. X#endif    /* INDEX_DAEMON */
  2278. X}
  2279. X
  2280. X
  2281. X/*
  2282. X**  User-level routine.  Returns TRUE or FALSE.
  2283. X*/
  2284. Xint
  2285. Xwildmat(text, p)
  2286. X    char    *text;
  2287. X    char    *p;
  2288. X{
  2289. X#ifdef    OPTIMIZE_JUST_STAR
  2290. X    if (p[0] == '*' && p[1] == '\0')
  2291. X    return TRUE;
  2292. X#endif    /* OPTIMIZE_JUST_STAR */
  2293. X    return DoMatch(text, p) == TRUE;
  2294. X}
  2295. X
  2296. X
  2297. X
  2298. X#ifdef    TEST
  2299. X#include <stdio.h>
  2300. X
  2301. X/* Yes, we use gets not fgets.  Sue me. */
  2302. Xextern char    *gets();
  2303. X
  2304. X
  2305. Xmain()
  2306. X{
  2307. X    char     p[80];
  2308. X    char     text[80];
  2309. X
  2310. X    printf("Wildmat tester.  Enter pattern, then strings to test.\n");
  2311. X    printf("A blank line gets prompts for a new pattern; a blank pattern\n");
  2312. X    printf("exits the program.\n");
  2313. X
  2314. X    for ( ; ; ) {
  2315. X    printf("\nEnter pattern:  ");
  2316. X    (void)fflush(stdout);
  2317. X    if (gets(p) == NULL || p[0] == '\0')
  2318. X        break;
  2319. X    for ( ; ; ) {
  2320. X        printf("Enter text:  ");
  2321. X        (void)fflush(stdout);
  2322. X        if (gets(text) == NULL)
  2323. X        exit(0);
  2324. X        if (text[0] == '\0')
  2325. X        /* Blank line; go back and get a new pattern. */
  2326. X        break;
  2327. X        printf("      %s\n", wildmat(text, p) ? "YES" : "NO");
  2328. X    }
  2329. X    }
  2330. X
  2331. X    exit(0);
  2332. X    /* NOTREACHED */
  2333. X}
  2334. X#endif    /* TEST */
  2335. END_OF_FILE
  2336.   if test 4798 -ne `wc -c <'wildmat.c'`; then
  2337.     echo shar: \"'wildmat.c'\" unpacked with wrong size!
  2338.   fi
  2339.   # end of 'wildmat.c'
  2340. fi
  2341. echo shar: End of archive 10 \(of 14\).
  2342. cp /dev/null ark10isdone
  2343. MISSING=""
  2344. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2345.     if test ! -f ark${I}isdone ; then
  2346.     MISSING="${MISSING} ${I}"
  2347.     fi
  2348. done
  2349. if test "${MISSING}" = "" ; then
  2350.     echo You have unpacked all 14 archives.
  2351.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2352. else
  2353.     echo You still must unpack the following archives:
  2354.     echo "        " ${MISSING}
  2355. fi
  2356. exit 0
  2357. exit 0 # Just in case...
  2358.