home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume29 / tin / part07 < prev    next >
Encoding:
Text File  |  1992-03-27  |  50.4 KB  |  2,604 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  3. Subject:  v29i025:  tin - threaded full screen newsreader v1.1P1, Part07/12
  4. Message-ID: <1992Mar27.033727.3385@sparky.imd.sterling.com>
  5. X-Md4-Signature: 78a36baf750dfa78cdb26d86be66ebbc
  6. Date: Fri, 27 Mar 1992 03:37:27 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 29, Issue 25
  11. Archive-name: tin/part07
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 28, Issue 45-55
  14.  
  15. #!/bin/sh
  16. # this is tin.shar.07 (part 7 of tin1.1)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file misc.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 7; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping misc.c'
  34. else
  35. echo 'x - continuing file misc.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'misc.c' &&
  37. X     signal (SIGABRT, SIG_DFL);
  38. #endif
  39. X     kill (process_id, SIGABRT);
  40. X    exit(1);
  41. }
  42. X
  43. X
  44. void copy_fp (fp_ip, fp_op, prefix)
  45. X    FILE *fp_ip;
  46. X    FILE *fp_op;
  47. X    char *prefix;
  48. {
  49. X    extern int errno;
  50. X    char buf[8192];
  51. X
  52. X    if (prefix == (char *) 0) {
  53. X        while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  54. X            if (fprintf (fp_op, "%s", buf) == EOF) {
  55. X                sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  56. X                error_message (msg, "");
  57. X            }
  58. X        }
  59. X    } else {
  60. X        while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  61. X            if (fprintf (fp_op, "%s%s", prefix, buf) == EOF) {
  62. X                sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  63. X                error_message (msg, "");
  64. X            }
  65. X        }
  66. X    }
  67. }
  68. X
  69. X
  70. char *get_val (env, def)
  71. X    char *env;        /* Environment variable we're looking for    */
  72. X    char *def;        /* Default value if no environ value found    */
  73. {
  74. X    char *ptr;
  75. X
  76. X    if ((ptr = (char *) getenv(env)) != NULL)
  77. X        return (ptr);
  78. X    else
  79. X        return (def);
  80. }
  81. X
  82. X
  83. int invoke_editor (nam)
  84. X    char *nam;
  85. {
  86. X    char buf[LEN];
  87. X    char *my_editor;
  88. X    static char editor[LEN];
  89. X    static int first = TRUE;
  90. X
  91. X    if (first) {
  92. X        my_editor = (char *) getenv ("VISUAL");
  93. X
  94. X        strcpy (editor, my_editor != NULL ? my_editor : get_val ("EDITOR", DEFAULT_EDITOR));
  95. X        first = FALSE;
  96. X    }
  97. X
  98. #ifdef NO_START_LINE
  99. X    sprintf (buf, "%s %s", editor, nam);
  100. #else
  101. X    sprintf (buf, "%s +%d %s", editor, start_line_offset, nam);
  102. #endif
  103. X
  104. X    printf ("%s", buf);
  105. X    return invoke_cmd (buf);
  106. }
  107. X
  108. X
  109. void shell_escape ()
  110. {
  111. X    char shell[LEN];
  112. X    char *p;
  113. X
  114. #ifdef SIGTSTP
  115. X    SIGTYPE (*susp)();
  116. #endif
  117. X
  118. X    sprintf (msg, txt_shell_escape, default_shell_command);
  119. X    
  120. X    if (! prompt_string (msg, shell))
  121. X        strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  122. X
  123. X    for (p = shell; *p && (*p == ' ' || *p == '\t'); p++)
  124. X        continue;
  125. X
  126. X    if (*p) {
  127. X        my_strncpy (default_shell_command, p, LEN);
  128. X    } else {
  129. X        if (default_shell_command[0]) {
  130. X            my_strncpy (shell, default_shell_command, LEN);
  131. X        } else {
  132. X            strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  133. X        }
  134. X        p = shell;
  135. X    }
  136. X
  137. X    ClearScreen ();
  138. X    sprintf (msg, "Shell Command (%s)", p);
  139. X    center_line (0, TRUE, msg);
  140. X    MoveCursor (INDEX_TOP, 0);
  141. X    
  142. X    EndWin ();
  143. X    Raw (FALSE);
  144. X
  145. X    set_real_uid_gid ();
  146. X
  147. #ifdef SIGTSTP
  148. X    if (do_sigtstp)
  149. X        susp = signal (SIGTSTP, SIG_DFL);
  150. #endif
  151. X
  152. X    system (p);
  153. X
  154. #ifdef SIGTSTP
  155. X    if (do_sigtstp)
  156. X        signal (SIGTSTP, susp);
  157. #endif
  158. X
  159. X    set_tin_uid_gid ();
  160. X
  161. X    Raw (TRUE);
  162. X    InitWin ();
  163. X
  164. X    mail_setup ();
  165. X
  166. X    continue_prompt ();
  167. X
  168. X    if (draw_arrow_mark) {
  169. X        ClearScreen ();
  170. X    }
  171. }
  172. X
  173. X
  174. void tin_done (ret)
  175. X    int ret;
  176. {
  177. X    char group_path[LEN], *p;
  178. X    int ask = TRUE;
  179. X    register int i, j;
  180. X    
  181. X    /*
  182. X     * check if any groups were read & ask if they should marked read
  183. X     */
  184. X    if (catchup_read_groups) {
  185. X        for (i = 0 ; i < group_top ; i++) {
  186. X            if (active[my_group[i]].read) {
  187. X                if (ask) {
  188. X                    if (prompt_yn (LINES, "Catchup all groups entered during this session? (y/n): ", 'n')) {
  189. X                        ask = FALSE;
  190. X                        thread_arts = FALSE;    /* speeds up index loading */
  191. X                    } else {
  192. X                        break;
  193. X                    }
  194. X                }
  195. X                sprintf (msg, "Catchup %s...", active[my_group[i]].name);
  196. X                wait_message (msg);
  197. X                strcpy (group_path, active[my_group[i]].name);
  198. X                for (p = group_path; *p; p++) {
  199. X                    if (*p == '.') {
  200. X                        *p = '/';
  201. X                    }
  202. X                }
  203. X                index_group (active[my_group[i]].name, group_path);
  204. X                for (j = 0; j < top; j++) {
  205. X                    arts[j].unread = ART_READ;
  206. X                }
  207. X                update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  208. X            }
  209. X        }
  210. X    }
  211. X    nntp_finish ();            /* disconnect from NNTP server */
  212. X    free_all_arrays ();        /* deallocate all arrays */
  213. X    ClearScreen ();
  214. X    EndWin ();
  215. X    Raw (FALSE);
  216. X
  217. if (debug == 2) {
  218. X    {
  219. X    extern int test_reread;
  220. X    printf ("resync ran %d times with max_active of %d\n", test_reread, max_active);
  221. X    fflush (stdout);
  222. X    }
  223. }
  224. X
  225. X    exit (ret);
  226. }
  227. X
  228. /*
  229. X *  Mark any groups in my_group[] that are in ~/.tin/unthread so they
  230. X *  will not be threaded
  231. X */
  232. void mark_unthreaded_groups ()
  233. {
  234. X    FILE *fp;
  235. X    char buf[LEN];
  236. X    int i;
  237. X    long h;
  238. X
  239. #ifndef INDEX_DAEMON
  240. X
  241. X    set_real_uid_gid ();
  242. X    
  243. X    if ((fp = fopen (unthreadfile, "r")) == NULL) {
  244. X        error_message (txt_cannot_open, unthreadfile);
  245. X        set_tin_uid_gid ();
  246. X        return;
  247. X    }
  248. X
  249. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  250. X        buf[strlen (buf)-1] = '\0'; 
  251. X        h = hash_groupname (buf);
  252. X
  253. X        sprintf (msg, "Unthreading %s...\n", buf);
  254. X        wait_message (msg);
  255. X        
  256. X        for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
  257. X            if (strcmp (active[i].name, buf) == 0) {
  258. X                active[i].thread = FALSE;
  259. X                break;
  260. X            }
  261. X        }
  262. X    }
  263. X    fclose (fp);
  264. X    set_tin_uid_gid ();
  265. X
  266. #endif /* INDEX_DAEMON */
  267. }
  268. X
  269. #ifdef USE_MKDIR
  270. mkdir (path, mode)
  271. X    char *path;
  272. X    int mode;
  273. {
  274. X    char buf[LEN];
  275. X    struct stat sb;
  276. X
  277. X    sprintf(buf, "mkdir %s", path);
  278. X    if (stat (path, &sb) == -1) {
  279. X        system (buf);
  280. X        chmod (path, mode);
  281. X    }
  282. }
  283. #endif
  284. X
  285. /*
  286. X * hash group name for fast lookup later 
  287. X */
  288. X
  289. long hash_groupname (group)
  290. X    char *group;
  291. {
  292. X    unsigned long hash_value;
  293. X    unsigned char *ptr = (unsigned char *) group;
  294. X
  295. X    hash_value = *ptr++;
  296. X
  297. X    while (*ptr)
  298. X        hash_value = ((hash_value << 1) ^ *ptr++) % TABLE_SIZE;
  299. X
  300. X    return (hash_value);
  301. }
  302. X
  303. X
  304. void rename_file (old_filename, new_filename)
  305. X    char *old_filename;
  306. X    char *new_filename;
  307. {    
  308. X    char buf[LEN];
  309. X    
  310. X    unlink (new_filename);
  311. X    if (link (old_filename, new_filename) == 1) {
  312. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  313. X        error_message (buf, "TWO");
  314. X        return;
  315. X    }
  316. X    if (unlink (old_filename) == -1) {
  317. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  318. X        error_message (buf, "THREE");
  319. X        return;
  320. X    }
  321. }
  322. X
  323. X
  324. char *str_dup (str)
  325. X    char *str;
  326. {
  327. X    char *dup = (char *) 0;
  328. X
  329. X    assert (str != (char *) 0);
  330. X    
  331. X    if (str) {
  332. X        dup = my_malloc (strlen (str)+1);
  333. X        strcpy (dup, str);
  334. X    }
  335. X    return dup;
  336. }
  337. X
  338. X
  339. int invoke_cmd (nam)
  340. X    char *nam;
  341. {
  342. X    int ret;
  343. X    int time_remaining;
  344. X    
  345. #ifdef SIGTSTP
  346. X    SIGTYPE (*susp)();
  347. #endif
  348. X
  349. X    time_remaining = alarm (0);    /* save time remaining on alarm clock */
  350. X
  351. X    EndWin ();
  352. X    Raw (FALSE);
  353. X    set_real_uid_gid ();
  354. X
  355. #ifdef SIGTSTP
  356. X    if (do_sigtstp)
  357. X        susp = signal(SIGTSTP, SIG_DFL);
  358. #endif
  359. X
  360. X    ret = system (nam);
  361. X
  362. #ifdef SIGTSTP
  363. X    if (do_sigtstp)
  364. X        signal (SIGTSTP, susp);
  365. #endif
  366. X
  367. X    set_tin_uid_gid ();
  368. X
  369. X    Raw (TRUE);
  370. X    InitWin ();
  371. X
  372. X    alarm (time_remaining);    /* restart resync alarm clock */
  373. X    
  374. X    return ret == 0;
  375. }
  376. X
  377. X
  378. void draw_percent_mark (cur_num, max_num)
  379. X    int cur_num;
  380. X    int max_num;
  381. {
  382. X    char buf[32];
  383. X    int percent = 0;
  384. X
  385. X    if (NOTESLINES <= 0) {
  386. X        return;
  387. X    }
  388. X
  389. X    if (cur_num <= 0 && max_num <= 0) {
  390. X        return;
  391. X    }
  392. X        
  393. X    percent = cur_num * 100 / max_num;
  394. X    sprintf (buf, "%s(%d%%) [%d/%d]", txt_more, percent, cur_num, max_num);
  395. X    MoveCursor (LINES, (COLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS));
  396. X    StartInverse ();    
  397. X    printf ("%s", buf);
  398. X    fflush (stdout);
  399. X    EndInverse ();
  400. }
  401. X
  402. X
  403. void set_real_uid_gid ()
  404. {
  405. #if defined(BSD) && ! defined(sinix)
  406. #ifdef sun
  407. X    if (seteuid (real_uid) == -1) {
  408. X        error_message ("Error setreuid(real) failed", "");
  409. X    }
  410. X    if (setrgid (real_gid) == -1) {
  411. X        error_message ("Error setregid(real) failed", "");
  412. X    }
  413. #else
  414. X    if (setreuid (tin_uid, real_uid) == -1) {
  415. X        error_message ("Error setreuid(real) failed", "");
  416. X    }
  417. X    if (setregid (tin_gid, real_gid) == -1) {
  418. X        error_message ("Error setregid(real) failed", "");
  419. X    }
  420. #endif    /* sun */    
  421. #else
  422. X    if (setuid (real_uid) == -1) {
  423. X        error_message ("Error setuid(real) failed", "");
  424. X    }
  425. X    if (setgid (real_gid) == -1) {
  426. X        error_message ("Error setgid(real) failed", "");
  427. X    }
  428. #endif
  429. }
  430. X
  431. X
  432. void set_tin_uid_gid ()
  433. {
  434. #if defined(BSD) && ! defined(sinix)
  435. #ifdef sun
  436. X    if (seteuid (tin_uid) == -1) {
  437. X        error_message ("Error setreuid(real) failed", "");
  438. X    }
  439. X    if (setrgid (tin_gid) == -1) {
  440. X        error_message ("Error setregid(real) failed", "");
  441. X    }
  442. #else
  443. X    if (setreuid (real_uid, tin_uid) == -1) {
  444. X        error_message ("Error setreuid(tin) failed", "");
  445. X    }
  446. X    if (setregid (real_gid, tin_gid) == -1) {
  447. X        error_message ("Error setregid(tin) failed", "");
  448. X    }
  449. #endif    /* sun */    
  450. #else
  451. X    if (setuid (tin_uid) == -1) {
  452. X        error_message ("Error setuid(tin) failed", "");
  453. X    }
  454. X    if (setgid (tin_gid) == -1) {
  455. X        error_message ("Error setgid(tin) failed", "");
  456. X    }
  457. #endif
  458. }
  459. X
  460. X
  461. void basename (dirname, program)
  462. X    char *dirname;        /* argv[0] */
  463. X    char *program;        /* progname is returned */
  464. {
  465. X    int i;
  466. X    
  467. X    strcpy (program, dirname);
  468. X    
  469. X    for (i=(int) strlen (dirname)-1 ; i ; i--) {
  470. X        if (dirname[i] == '/') {
  471. X            strcpy (program, dirname+(i+1));
  472. X            break;
  473. X        }
  474. X    }
  475. }
  476. X
  477. X
  478. /*
  479. X *  Record size of mailbox so we can detect if new mail has arrived
  480. X */
  481. X
  482. void mail_setup ()
  483. {
  484. X    struct stat buf;
  485. X
  486. X    mailbox_name = get_val ("MAIL", mailbox);
  487. X
  488. X    if (stat (mailbox_name, &buf) >= 0) {
  489. X        mailbox_size = buf.st_size;
  490. X    } else {
  491. X        mailbox_size = 0;
  492. X    }
  493. }
  494. X
  495. /*
  496. X *  Return TRUE if new mail has arrived
  497. X */
  498. X
  499. int mail_check ()
  500. {
  501. X    struct stat buf;
  502. X
  503. X    if (mailbox_name != (char *) 0 &&
  504. X        stat(mailbox_name, &buf) >= 0 &&
  505. X        mailbox_size < buf.st_size) {
  506. X        return TRUE;
  507. X    }
  508. X
  509. X    return FALSE;
  510. }
  511. X
  512. /*
  513. X *  Parse various From: lines into the component mail addresses and
  514. X *  real names
  515. X */
  516. X
  517. void parse_from (str, addr, name)
  518. X    char *str;
  519. X    char *addr;
  520. X    char *name;
  521. {
  522. X    register int c;
  523. X    register char *cp, *ncp;
  524. X    int gotlt, lastsp, level;
  525. X
  526. X    gotlt = 0;
  527. X    lastsp = 0;
  528. X    cp = addr;
  529. X    ncp = name;
  530. X    while (*str == ' ')
  531. X        ++str;
  532. X    while (c = *str++)
  533. X        switch (c) {
  534. X        case '(':
  535. X            ncp = name;
  536. X            level = 1;
  537. X            while (*str != '\0' && level) {
  538. X                switch (c = *str++) {
  539. X                case '(':
  540. X                    *ncp++ = c;
  541. X                    level++;
  542. X                    break;
  543. X                case ')':
  544. X                    level--;
  545. X                    if (level > 0)
  546. X                        *ncp++ = c;
  547. X                    break;
  548. X                default:
  549. X                    *ncp++ = c;
  550. X                    break;
  551. X                }
  552. X            }
  553. X            if (*str)
  554. X                str++;
  555. X            lastsp = 0;
  556. X            break;
  557. X        case ' ':
  558. X            if (str[0] == 'a' && str[1] == 't' && str[2] == ' ')
  559. X                str += 3, *cp++ = '@';
  560. X            else if (str[0] == '@' && str[1] == ' ')
  561. X                str += 2, *cp++ = '@';
  562. X            else
  563. X                lastsp = 1;
  564. X            if (ncp > name)
  565. X                *ncp++ = ' ';
  566. X            break;
  567. X        case '<':
  568. X            cp = addr;
  569. X            gotlt++;
  570. X            lastsp = 0;
  571. X            break;
  572. X        case '>':
  573. X            if (gotlt)
  574. X                goto done;
  575. X            /* FALL THROUGH CASE */
  576. X        default:
  577. X            if (lastsp) {
  578. X                lastsp = 0;
  579. X                *cp++ = ' ';
  580. X            }
  581. X            *cp++ = c;
  582. X            if (! gotlt)
  583. X                *ncp++ = c;
  584. X            break;
  585. X        }
  586. done:
  587. X    *cp = 0;
  588. X    while (ncp>name && ncp[-1]==' ')
  589. X        --ncp;
  590. X    *ncp = 0;
  591. X    if (*addr == '@') {
  592. X        char buf [512];
  593. X
  594. X        strcpy (buf, addr);
  595. X        strcpy (addr, "root");
  596. X        strcat (addr, buf);
  597. X    }
  598. }
  599. X
  600. /*
  601. X *  Convert a string to a long, only look at first n characters
  602. X */
  603. X
  604. long my_atol (s, n)
  605. X    char *s;
  606. X    int n;
  607. {
  608. X    long ret = 0;
  609. X
  610. X    while (*s && n--) {
  611. X        if (*s >= '0' && *s <= '9')
  612. X            ret = ret * 10 + (*s - '0');
  613. X        else
  614. X            return -1;
  615. X        s++;
  616. X    }
  617. X
  618. X    return ret;
  619. }
  620. X
  621. /*
  622. X *  Return a pointer into s eliminating any leading Re:'s.  Example:
  623. X *
  624. X *      Re: Reorganization of misc.jobs
  625. X *      ^   ^
  626. X */
  627. X
  628. char *eat_re (s)
  629. X    char *s;
  630. {
  631. X
  632. X    while (*s == 'r' || *s == 'R') {
  633. X        if ((*(s+1) == 'e' || *(s+1) == 'E')) {
  634. X            if (*(s+2) == ':')
  635. X                s += 3;
  636. X            else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':')
  637. X                s += 5;            /* hurray nn */
  638. X            else
  639. X                break;
  640. X        } else
  641. X            break;
  642. X        while (*s == ' ')
  643. X            s++;
  644. X    }
  645. X
  646. X    return s;
  647. }
  648. X
  649. /*
  650. X *  Hash the subjects (after eating the Re's off) for a quicker
  651. X *  thread search later.  We store the hashes for subjects in the
  652. X *  index file for speed.
  653. X */
  654. X
  655. long hash_s (s)
  656. X    char *s;
  657. {
  658. X    long h = 0;
  659. X    unsigned char *t = (unsigned char *) s;
  660. X
  661. X    while (*t)
  662. X        h = h * 64 + *t++;
  663. X
  664. X    return h;
  665. }
  666. X
  667. /*
  668. X *  strncpy that stops at a newline and null terminates
  669. X */
  670. X
  671. void my_strncpy(p, q, n)
  672. X    char *p;
  673. X    char *q;
  674. X    int n;
  675. {
  676. X    while (n--) {
  677. X        if (! *q || *q == '\n')
  678. X            break;
  679. X        *p++ = *q++;
  680. X    }
  681. X    *p = '\0';
  682. }
  683. X
  684. X
  685. int untag_all_articles ()
  686. {
  687. X    int untagged = FALSE;
  688. X    register int i;
  689. X
  690. X    for (i=0 ; i < top ; i++) {
  691. X        if (arts[i].tagged) {
  692. X            arts[i].tagged = FALSE;
  693. X            untagged = TRUE;
  694. X        }
  695. X    }
  696. X    num_of_tagged_files = 0;
  697. X
  698. X    return (untagged);
  699. }
  700. X
  701. X
  702. /*
  703. X * ANSI C strstr () - Uses Boyer-Moore algorithm. Downloaded from net.
  704. X */
  705. char *str_str (text, pattern, patlen)
  706. X    char *text;
  707. X    char *pattern;
  708. X    int patlen;
  709. {
  710. X    register unsigned char *p, *t;
  711. X    register int i, p1, j, *delta;
  712. X    int deltaspace[256];
  713. X    int textlen;
  714. X
  715. X    textlen = strlen (text);
  716. X
  717. X    /* algorithm fails if pattern is empty */
  718. X    if ((p1 = patlen) == 0)
  719. X        return (text);
  720. X
  721. X    /* code below fails (whenever i is unsigned) if pattern too long */
  722. X    if (p1 > textlen)
  723. X        return (NULL);
  724. X
  725. X    /* set up deltas */
  726. X    delta = deltaspace;
  727. X    for (i = 0; i <= 255; i++)
  728. X        delta[i] = p1;
  729. X    for (p = (unsigned char *) pattern, i = p1; --i > 0;)
  730. X        delta[*p++] = i;
  731. X
  732. X    /*
  733. X     * From now on, we want patlen - 1.
  734. X     * In the loop below, p points to the end of the pattern,
  735. X     * t points to the end of the text to be tested against the
  736. X     * pattern, and i counts the amount of text remaining, not
  737. X     * including the part to be tested.
  738. X     */
  739. X    p1--;
  740. X    p = (unsigned char *) pattern + p1;
  741. X    t = (unsigned char *) text + p1;
  742. X    i = textlen - patlen;
  743. X    for (;;) {
  744. X        if (*p == *t && memcmp((p - p1), (t - p1), p1) == 0)
  745. X            return ((char *)t - p1);
  746. X        j = delta[*t];
  747. X        if (i < j)
  748. X            break;
  749. X        i -= j;
  750. X        t += j;
  751. X    }
  752. X    return (NULL);
  753. }
  754. X
  755. X
  756. void get_author (thread, respnum, str)
  757. X    int thread;
  758. X    int respnum;
  759. X    char *str;
  760. {    
  761. X    extern int threaded_on_subject;
  762. X    int author;
  763. X    int len_from = max_from;
  764. X    
  765. X    if (thread) {
  766. X        if (threaded_on_subject) {
  767. X            len_from = max_subj+max_from;
  768. X        } else {
  769. X            len_from = max_from;
  770. X        }
  771. X        author = SHOW_FROM_BOTH;
  772. X    } else {
  773. X        author = show_author;
  774. X    }
  775. X
  776. X    switch (author) {
  777. X        case SHOW_FROM_ADDR:
  778. X            my_strncpy (str, arts[respnum].from, len_from);
  779. X            break;
  780. X        case SHOW_FROM_NAME:
  781. X            my_strncpy (str, arts[respnum].name, len_from);
  782. X            break;
  783. X        case SHOW_FROM_BOTH:
  784. X            if (arts[respnum].name != arts[respnum].from) { 
  785. X                sprintf (msg, "%s (%s)", arts[respnum].name, arts[respnum].from);
  786. X                my_strncpy (str, msg, len_from);
  787. X            } else { 
  788. X                my_strncpy (str, arts[respnum].from, len_from);
  789. X            }
  790. X            break;
  791. X    }
  792. }
  793. X
  794. X
  795. void toggle_inverse_video ()
  796. {
  797. X    inverse_okay = !inverse_okay;
  798. X    if (inverse_okay) {
  799. #ifndef USE_INVERSE_HACK    
  800. X        draw_arrow_mark = FALSE;
  801. #endif        
  802. X        info_message (txt_inverse_on);
  803. X    } else {
  804. X        draw_arrow_mark = TRUE;
  805. X        info_message (txt_inverse_off);
  806. X    }
  807. }
  808. X
  809. X
  810. int get_arrow_key ()
  811. {
  812. X    int ch;
  813. X    
  814. X    ch = ReadCh ();
  815. X    if (ch == '[' || ch == 'O')
  816. X        ch = ReadCh();
  817. X    switch (ch) {
  818. X        case 'A':
  819. X        case 'D':
  820. X        case 'i':
  821. X            return KEYMAP_UP;
  822. X
  823. X        case 'B':
  824. X        case 'C':
  825. X            return KEYMAP_DOWN;
  826. X
  827. X        case 'I':        /* ansi  PgUp */
  828. X        case 'V':        /* at386 PgUp */
  829. X        case 'S':        /* 97801 PgUp */
  830. X        case 'v':        /* emacs style */
  831. X            return KEYMAP_PAGE_UP;
  832. X
  833. X        case 'G':        /* ansi  PgDn */
  834. X        case 'U':        /* at386 PgDn */
  835. X        case 'T':        /* 97801 PgDn */
  836. X            return KEYMAP_PAGE_DOWN;
  837. X
  838. X        case 'H':        /* at386  Home */
  839. X            return KEYMAP_HOME;
  840. X                    
  841. X        case 'F':        /* ansi  End */
  842. X        case 'Y':        /* at386  End */
  843. X            return KEYMAP_END;
  844. X
  845. X        default:
  846. X            return KEYMAP_UNKNOWN;
  847. X    }
  848. }
  849. SHAR_EOF
  850. echo 'File misc.c is complete' &&
  851. chmod 0600 misc.c ||
  852. echo 'restore of misc.c failed'
  853. Wc_c="`wc -c < 'misc.c'`"
  854. test 15357 -eq "$Wc_c" ||
  855.     echo 'misc.c: original size 15357, current size' "$Wc_c"
  856. rm -f _shar_wnt_.tmp
  857. fi
  858. # ============= newsrc.c ==============
  859. if test -f 'newsrc.c' -a X"$1" != X"-c"; then
  860.     echo 'x - skipping newsrc.c (File already exists)'
  861.     rm -f _shar_wnt_.tmp
  862. else
  863. > _shar_wnt_.tmp
  864. echo 'x - extracting newsrc.c (Text)'
  865. sed 's/^X//' << 'SHAR_EOF' > 'newsrc.c' &&
  866. /*
  867. X *  Project   : tin - a threaded Netnews reader
  868. X *  Module    : newsrc.c
  869. X *  Author    : I.Lea & R.Skrenta
  870. X *  Created   : 01-04-91
  871. X *  Updated   : 19-03-92
  872. X *  Notes     :
  873. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  874. X *              You may  freely  copy or  redistribute  this software,
  875. X *              so  long as there is no profit made from its use, sale
  876. X *              trade or  reproduction.  You may not change this copy-
  877. X *              right notice, and it must be included in any copy made
  878. X */
  879. X
  880. #include    "tin.h"
  881. X
  882. X
  883. /*
  884. X * Automatically subscribe user to newsgroups specified in
  885. X * /usr/lib/news/subscribe (locally) or same file but from
  886. X * NNTP server (LIST AUTOSUBSCRIBE) and create .newsrc
  887. X */
  888. X
  889. int auto_subscribe_groups ()
  890. {
  891. X    char buf[LEN];
  892. X    FILE *fp_newsrc;
  893. X    FILE *fp_subs;
  894. X    int len;
  895. X    int ret_code = FALSE;
  896. X    
  897. X    set_real_uid_gid ();
  898. X
  899. X    if ((fp_subs = open_subscription_fp ()) != NULL) {
  900. X        if ((fp_newsrc = fopen (newsrc, "w")) != NULL) {
  901. X            while (fgets (buf, sizeof (buf), fp_subs) != NULL) {
  902. X                len = strlen (buf);
  903. X                if (len > 1) {
  904. X                    buf[len-1] = '\0';
  905. X                    fprintf (fp_newsrc, "%s:\n", buf);
  906. X                }    
  907. X            }    
  908. X            fclose (fp_newsrc);
  909. X            ret_code = TRUE;
  910. X        }    
  911. X        fclose (fp_subs);
  912. X    }
  913. X
  914. X    set_tin_uid_gid ();
  915. X    
  916. X    return (ret_code);
  917. }
  918. X
  919. /*
  920. X * make a backup of users .newsrc in case of the bogie man
  921. X */
  922. X
  923. void backup_newsrc ()
  924. {
  925. X    char buf[8192];
  926. X    FILE *fp_newsrc, *fp_backup;
  927. X    
  928. X    set_real_uid_gid ();
  929. X
  930. X    if ((fp_newsrc = fopen (newsrc, "r")) != NULL) {
  931. X        sprintf (buf, "%s/.oldnewsrc", homedir);
  932. X        unlink (buf);    /* because rn makes a link of .newsrc -> .oldnewsrc */
  933. X        if ((fp_backup = fopen (buf, "w")) != NULL) {
  934. X            while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) {
  935. X                fputs (buf, fp_backup);
  936. X            }
  937. X            fclose (fp_backup);
  938. X        }
  939. X        fclose (fp_newsrc);
  940. X    }
  941. X
  942. X    set_tin_uid_gid ();
  943. }
  944. X
  945. /*
  946. X *  Read $HOME/.newsrc into my_group[]. my_group[] ints point to
  947. X *  active[] entries.  Sub_only determines  whether to just read
  948. X *  subscribed groups or all of them.
  949. X */
  950. X
  951. void read_newsrc (sub_only)
  952. X    int sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  953. {
  954. X    char c, *p, buf[8192];
  955. X    char old_groups[LEN];
  956. X    FILE *fp, *fp_old;
  957. X    int i;
  958. X    int remove_old_groups = FALSE;
  959. X
  960. X    group_top = 0;
  961. X
  962. reread_newsrc:
  963. X
  964. X    set_real_uid_gid ();
  965. X    
  966. X    if ((fp = fopen (newsrc, "r")) == NULL) {    /* attempt to make a .newsrc */
  967. X        if (auto_subscribe_groups ()) {        /* attempt to auto create newsrc */
  968. X            goto reread_newsrc;
  969. X        }    
  970. X        for (i = 0; i < num_active; i++) {
  971. X            if (group_top >= max_active) {
  972. X                expand_active ();
  973. X            }
  974. X            my_group[group_top] = i;
  975. X            active[i].flag = 0;
  976. X            unread[group_top] = -1;
  977. X            group_top++;
  978. X        }
  979. X        write_newsrc ();
  980. X        return;
  981. X    }
  982. X
  983. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  984. X
  985. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  986. X        p = buf;
  987. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  988. X            p++;
  989. X        c = *p;
  990. X        *p++ = '\0';
  991. X
  992. X        if (c == '!' && sub_only)
  993. X            continue;        /* unsubscribed */
  994. X
  995. X        if ((i = add_group (buf, FALSE)) < 0) {
  996. X            if (! remove_old_groups) {
  997. X                if ((fp_old = fopen (old_groups, "w")) == NULL) {
  998. X                    error_message (txt_cannot_open, old_groups);
  999. X                    continue;
  1000. X                }
  1001. X                remove_old_groups = TRUE;
  1002. X            }
  1003. X            fprintf (fp_old, "%s\n", buf);
  1004. X            continue;
  1005. X        }
  1006. X
  1007. X        if (c != '!')        /* if we're subscribed to it */
  1008. X            active[my_group[i]].flag |= SUBSCRIBED;
  1009. X
  1010. X        unread[i] = parse_unread (p, my_group[i]);
  1011. X    }
  1012. X    fclose (fp);
  1013. X
  1014. X    /*
  1015. X     *  rewrite newsrc to get rid of any non-existant groups 
  1016. X     */
  1017. X    if (remove_old_groups) {
  1018. X        fclose (fp_old);
  1019. X        rewrite_newsrc ();
  1020. X    }
  1021. X
  1022. X    set_tin_uid_gid ();
  1023. }
  1024. X
  1025. /*
  1026. X *  Write a new newsrc from my_group[] and active[] mygroup if
  1027. X *  rewriting to get rid of groups that don't exist any longer. Used
  1028. X *  to a create a new .newsrc if there isn't one already, or when
  1029. X *  the newsrc is reset.
  1030. X */
  1031. X
  1032. void write_newsrc ()
  1033. {
  1034. X    FILE *fp;
  1035. X    int i;
  1036. X
  1037. X    set_real_uid_gid ();
  1038. X
  1039. X    if ((fp = fopen (newsrc, "w")) == NULL) {
  1040. X        set_tin_uid_gid ();
  1041. X        return;
  1042. X    }
  1043. X
  1044. X    wait_message (txt_creating_newsrc);
  1045. X
  1046. X    for (i=0 ; i < num_active ; i++) {
  1047. X        fprintf (fp, "%s! \n", active[i].name);
  1048. X    }
  1049. X
  1050. X    fclose (fp);
  1051. X
  1052. X    set_tin_uid_gid ();
  1053. }
  1054. X
  1055. /*
  1056. X *  Rewrite newsrc to get rid of groups that don't exist any longer.
  1057. X */
  1058. X
  1059. void rewrite_newsrc ()
  1060. {
  1061. X    char buf[8192], old[LEN];
  1062. X    char old_groups[LEN];
  1063. X    FILE *fp, *fp_old, *fp_new;
  1064. X    int found_old_group, len;    
  1065. X
  1066. X    set_real_uid_gid ();
  1067. X
  1068. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  1069. X
  1070. X    if ((fp = fopen (newsrc, "r")) == NULL)
  1071. X        goto removed_old_groups_done;
  1072. X
  1073. X    if ((fp_old = fopen (old_groups, "r")) == NULL)
  1074. X        goto removed_old_groups_done;
  1075. X
  1076. X    if ((fp_new = fopen (newnewsrc, "w")) == NULL)
  1077. X        goto removed_old_groups_done;
  1078. X
  1079. X    while (fgets (buf, sizeof buf, fp) != NULL) {            /* read group from newsrc */
  1080. X        rewind (fp_old);
  1081. X        found_old_group = FALSE;    
  1082. X        while (fgets (old, sizeof old, fp_old) != NULL) {    /* read group from oldgroups */
  1083. X            len = strlen (old)-1;
  1084. X            if ((buf[len] == ':' || buf[len] == '!') &&
  1085. X                strncmp (buf, old, len) == 0) {
  1086. X                old[len] = '\0';
  1087. X                sprintf (msg, txt_deleting_from_newsrc, old);
  1088. X                wait_message (msg);
  1089. X                if (cmd_line) {
  1090. X                    wait_message ("\n");
  1091. X                }    
  1092. X                found_old_group = TRUE;    
  1093. X            }
  1094. X        }
  1095. X        if (! found_old_group) {
  1096. X            fprintf (fp_new, "%s", buf);
  1097. X        }
  1098. X    }
  1099. X    
  1100. X    fclose (fp);
  1101. X    fclose (fp_old);
  1102. X    fclose (fp_new);
  1103. X
  1104. X    rename_file (newnewsrc, newsrc);
  1105. X
  1106. removed_old_groups_done:
  1107. X    unlink (old_groups);
  1108. X    set_tin_uid_gid ();
  1109. }
  1110. X
  1111. /*
  1112. X *  Load the sequencer rang lists and mark arts[] according to the
  1113. X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  1114. X */
  1115. X
  1116. void read_newsrc_line (group)
  1117. X    char *group;
  1118. {
  1119. X    FILE *fp;
  1120. X    char buf[8192];
  1121. X    char *p;
  1122. X
  1123. X    if ((fp = fopen (newsrc, "r")) == NULL)
  1124. X        return;
  1125. X
  1126. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  1127. X        p = buf;
  1128. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1129. X            p++;
  1130. X        *p++ = '\0';
  1131. X        if (strcmp (buf, group) != 0)
  1132. X            continue;
  1133. X        parse_seq (p);
  1134. X        break;
  1135. X    }
  1136. X
  1137. X    fclose (fp);
  1138. }
  1139. X
  1140. /*
  1141. X *  For our current group, update the sequencer information in .newsrc
  1142. X */
  1143. X
  1144. void update_newsrc (group, groupnum, mark_unread)
  1145. X    char *group;
  1146. X    int groupnum;            /* index into active[] for this group */
  1147. X    int mark_unread;
  1148. {
  1149. X    FILE *fp;
  1150. X    FILE *newfp;
  1151. X    char buf[8192];
  1152. X    char *p;
  1153. X    char c;
  1154. X
  1155. X    set_real_uid_gid ();
  1156. X
  1157. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1158. X        goto update_done;
  1159. X
  1160. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1161. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  1162. X            for (p = buf; *p; p++)
  1163. X                if (*p == '\n') {
  1164. X                    *p = '\0';
  1165. X                    break;
  1166. X                }
  1167. X
  1168. X            p = buf;
  1169. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1170. X                    p++;
  1171. X            c = *p;
  1172. X            if (c != '\0')
  1173. X                *p++ = '\0';
  1174. X
  1175. X            if (c != '!' && c != ' ')
  1176. X                c = ':';
  1177. X
  1178. X            if (strcmp (buf, group) == 0) {
  1179. X                if (mark_unread) {
  1180. X                    fprintf (newfp, "%s%c\n", buf, c);
  1181. X                } else {
  1182. X                    fprintf (newfp, "%s%c ", buf, c);
  1183. X                    print_seq (newfp, groupnum);
  1184. X                    fprintf (newfp, "\n");
  1185. X                }
  1186. X            } else
  1187. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  1188. X        }
  1189. X        fclose (fp);
  1190. X    }
  1191. X
  1192. X    fclose (newfp);
  1193. X    rename_file (newnewsrc, newsrc);
  1194. X
  1195. update_done:
  1196. X    set_tin_uid_gid ();
  1197. }
  1198. X
  1199. /*
  1200. X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  1201. X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  1202. X *  in active[].
  1203. X */
  1204. X
  1205. void subscribe (group, ch, num, out_seq)
  1206. X    char *group;
  1207. X    char ch;
  1208. X    int num;
  1209. X    int out_seq;                /* output sequencer info? */
  1210. {
  1211. X    FILE *fp;
  1212. X    FILE *newfp;
  1213. X    char buf[8192];
  1214. X    char *p;
  1215. X    char c;
  1216. X    int gotit = FALSE;
  1217. X
  1218. X    if (ch == '!')
  1219. X        active[num].flag &= ~SUBSCRIBED;
  1220. X    else
  1221. X        active[num].flag |= SUBSCRIBED;
  1222. X
  1223. X    set_real_uid_gid ();
  1224. X
  1225. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1226. X        goto subscribe_done;
  1227. X
  1228. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1229. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  1230. X            if (strncmp ("options ", buf, 8) == 0) {
  1231. X                fprintf (newfp, buf);
  1232. X            } else {
  1233. X                for (p = buf; *p; p++) {
  1234. X                    if (*p == '\n') {
  1235. X                        *p = '\0';
  1236. X                        break;
  1237. X                    }
  1238. X                }    
  1239. X
  1240. X                p = buf;
  1241. X                while (*p && *p != ' ' && *p != ':' && *p != '!')
  1242. X                        p++;
  1243. X                c = *p;
  1244. X                if (c != '\0')
  1245. X                    *p++ = '\0';
  1246. X
  1247. X                if (c != '!')
  1248. X                    c = ':';
  1249. X
  1250. X                if (strcmp (buf, group) == 0) {
  1251. X                    fprintf (newfp, "%s%c%s\n", buf, ch, p);
  1252. X                    gotit = TRUE;
  1253. X                } else {
  1254. X                    fprintf (newfp, "%s%c%s\n", buf, c, p);
  1255. X                }
  1256. X            }
  1257. X        }
  1258. X        fclose (fp);
  1259. X    }
  1260. X
  1261. X    if (! gotit) {
  1262. X        if (out_seq) {
  1263. X            fprintf (newfp, "%s%c ", group, ch);
  1264. X            print_seq (newfp, num);
  1265. X            fprintf (newfp, "\n");
  1266. X        } else
  1267. X            fprintf (newfp, "%s%c\n", group, ch);
  1268. X    }
  1269. X
  1270. X    fclose (newfp);
  1271. X    rename_file (newnewsrc, newsrc);
  1272. X
  1273. subscribe_done:
  1274. X    set_tin_uid_gid ();
  1275. }
  1276. X
  1277. X
  1278. void reset_newsrc ()
  1279. {
  1280. X    FILE *fp;
  1281. X    FILE *newfp;
  1282. X    char buf[8192];
  1283. X    char *p;
  1284. X    char c;
  1285. X    int i;
  1286. X
  1287. X    set_real_uid_gid ();
  1288. X
  1289. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1290. X        goto update_done;
  1291. X
  1292. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1293. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1294. X            for (p = buf; *p && *p != '\n'; p++)
  1295. X                continue;
  1296. X            *p = '\0';
  1297. X
  1298. X            p = buf;
  1299. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1300. X                    p++;
  1301. X            c = *p;
  1302. X            if (c != '\0')
  1303. X                *p++ = '\0';
  1304. X
  1305. X            if (c != '!')
  1306. X                c = ':';
  1307. X
  1308. X            fprintf (newfp, "%s%c\n", buf, c);
  1309. X        }
  1310. X        fclose (fp);
  1311. X    }
  1312. X
  1313. X    fclose (newfp);
  1314. X    rename_file (newnewsrc, newsrc);
  1315. X
  1316. update_done:
  1317. X    set_tin_uid_gid ();
  1318. X
  1319. X    for (i = 0; i < group_top; i++)
  1320. X        unread[i] = -1;
  1321. }
  1322. X
  1323. X
  1324. void delete_group (group)
  1325. X    char *group;
  1326. {
  1327. X    FILE *fp;
  1328. X    FILE *newfp;
  1329. X    char buf[8192];
  1330. X    char *p;
  1331. X    char c;
  1332. X    int gotit = FALSE;
  1333. X    FILE *del;
  1334. X
  1335. X    set_real_uid_gid ();
  1336. X
  1337. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1338. X        goto del_done;
  1339. X
  1340. X    if ((del = fopen (delgroups, "a+")) == NULL)
  1341. X        goto del_done;
  1342. X
  1343. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1344. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1345. X            for (p = buf; *p && *p != '\n'; p++)
  1346. X                continue;
  1347. X            *p = '\0';
  1348. X
  1349. X            p = buf;
  1350. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1351. X                    p++;
  1352. X            c = *p;
  1353. X            if (c != '\0')
  1354. X                *p++ = '\0';
  1355. X
  1356. X            if (c != '!')
  1357. X                c = ':';
  1358. X
  1359. X            if (strcmp (buf, group) == 0) {
  1360. X                fprintf (del, "%s%c%s\n", buf, c, p);
  1361. X                gotit = TRUE;
  1362. X            } else
  1363. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  1364. X        }
  1365. X        fclose (fp);
  1366. X    }
  1367. X
  1368. X    fclose (newfp);
  1369. X
  1370. X    if (! gotit)
  1371. X        fprintf (del, "%s! \n", group);
  1372. X
  1373. X    fclose (del);
  1374. X    rename_file (newnewsrc, newsrc);
  1375. X
  1376. del_done:
  1377. X    set_tin_uid_gid ();
  1378. }
  1379. X
  1380. X
  1381. int undel_group ()
  1382. {
  1383. X    FILE *del;
  1384. X    FILE *newfp;
  1385. X    FILE *fp;
  1386. X    char buf[2][8192];
  1387. X    char *p;
  1388. X    int which = 0;
  1389. X    long h;
  1390. X    extern int cur_groupnum;
  1391. X    int i, j;
  1392. X    char c;
  1393. X
  1394. X    set_real_uid_gid ();
  1395. X
  1396. X    if ((del = fopen(delgroups, "r")) == NULL) {
  1397. X        set_tin_uid_gid ();
  1398. X        return FALSE;
  1399. X    }
  1400. X
  1401. X    unlink(delgroups);
  1402. X    
  1403. X    if ((newfp = fopen(delgroups, "w")) == NULL) {
  1404. X        set_tin_uid_gid ();
  1405. X        return FALSE;
  1406. X    }
  1407. X
  1408. X    buf[0][0] = '\0';
  1409. X    buf[1][0] = '\0';
  1410. X
  1411. X    while (fgets(buf[which], sizeof (buf[which]), del) != NULL) {
  1412. X        which = !which;
  1413. X        if (*buf[which])
  1414. X            fputs(buf[which], newfp);
  1415. X    }
  1416. X
  1417. X    fclose(del);
  1418. X    fclose(newfp);
  1419. X    which = !which;
  1420. X
  1421. X    if (!*buf[which]) {
  1422. X        set_tin_uid_gid ();
  1423. X        return FALSE;
  1424. X    }
  1425. X
  1426. X    for (p = buf[which]; *p && *p != '\n'; p++)
  1427. X        continue;
  1428. X    *p = '\0';
  1429. X
  1430. X    p = buf[which];
  1431. X    while (*p && *p != ' ' && *p != ':' && *p != '!')
  1432. X        p++;
  1433. X    c = *p;
  1434. X    if (c != '\0')
  1435. X        *p++ = '\0';
  1436. X
  1437. X    if (c != '!')
  1438. X        c = ':';
  1439. X
  1440. X    h = hash_groupname (buf[which]);
  1441. X
  1442. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  1443. X        if (strcmp(buf[which], active[i].name) == 0) {
  1444. X            for (j = 0; j < group_top; j++)
  1445. X                if (my_group[j] == i) {
  1446. X                    set_tin_uid_gid ();
  1447. X                    return j;
  1448. X                }
  1449. X
  1450. X            active[i].flag &= ~UNSUBSCRIBED;   /* mark that we got it */
  1451. X            if (c != '!')
  1452. X                active[i].flag |= SUBSCRIBED;
  1453. X
  1454. X            if (group_top >= max_active)
  1455. X                expand_active ();
  1456. X            group_top++;
  1457. X            for (j = group_top; j > cur_groupnum; j--) {
  1458. X                my_group[j] = my_group[j-1];
  1459. X                unread[j] = unread[j-1];
  1460. X            }
  1461. X            my_group[cur_groupnum] = i;
  1462. X            unread[cur_groupnum] = parse_unread(p, i);
  1463. X
  1464. X            if ((fp = fopen(newsrc, "r")) == NULL) {
  1465. X                set_tin_uid_gid ();
  1466. X                return FALSE;
  1467. X            }
  1468. X            if ((newfp = fopen(newnewsrc, "w")) == NULL) {
  1469. X                fclose(fp);
  1470. X                set_tin_uid_gid ();
  1471. X                return FALSE;
  1472. X            }
  1473. X            i = 0;
  1474. X            while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) {
  1475. X                for (p = buf[!which]; *p && *p != '\n'; p++)
  1476. X                    continue;
  1477. X                *p = '\0';
  1478. X
  1479. X                p = buf[!which];
  1480. X                while (*p && *p!=' ' && *p != ':' && *p != '!')
  1481. X                    p++;
  1482. X                c = *p;
  1483. X                if (c != '\0')
  1484. X                    *p++ = '\0';
  1485. X
  1486. X                if (c != '!')
  1487. X                    c = ':';
  1488. X
  1489. X                while (i < cur_groupnum) {
  1490. X                    if (strcmp(buf[!which],
  1491. X                      active[my_group[i]].name) == 0) {
  1492. X                        fprintf(newfp, "%s%c%s\n",
  1493. X                            buf[!which], c, p);
  1494. X                        goto foo_cont;
  1495. X                    }
  1496. X                    i++;
  1497. X                }
  1498. X                fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  1499. X                fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  1500. X                break;
  1501. foo_cont:;
  1502. X            }
  1503. X
  1504. X            while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL)
  1505. X                fputs (buf[!which], newfp);
  1506. X
  1507. X            fclose (newfp);
  1508. X            fclose (fp);
  1509. X            rename_file (newnewsrc, newsrc);
  1510. X            set_tin_uid_gid ();
  1511. X            return TRUE;
  1512. X        }
  1513. X    }
  1514. X    set_tin_uid_gid ();
  1515. X
  1516. X    return FALSE;
  1517. }
  1518. X
  1519. X
  1520. void mark_group_read (group, groupnum)
  1521. X    char *group;
  1522. X    int groupnum;            /* index into active[] for this group */
  1523. {
  1524. X    FILE *fp;
  1525. X    FILE *newfp;
  1526. X    char buf[8192];
  1527. X    char *p;
  1528. X    char c;
  1529. X
  1530. X    if (active[groupnum].max < 2)
  1531. X        return;
  1532. X
  1533. X    set_real_uid_gid ();
  1534. X
  1535. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1536. X        goto mark_group_read_done;
  1537. X
  1538. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1539. X        while (fgets(buf, sizeof (buf), fp) != NULL) {
  1540. X            for (p = buf; *p; p++)
  1541. X                if (*p == '\n') {
  1542. X                    *p = '\0';
  1543. X                    break;
  1544. X                }
  1545. X
  1546. X            p = buf;
  1547. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1548. X                    p++;
  1549. X            c = *p;
  1550. X            if (c != '\0')
  1551. X                *p++ = '\0';
  1552. X
  1553. X            if (c != '!')
  1554. X                c = ':';
  1555. X
  1556. X            if (strcmp (buf, group) == 0) {
  1557. X                fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max);
  1558. X            } else
  1559. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  1560. X        }
  1561. X        fclose (fp);
  1562. X    }
  1563. X
  1564. X    fclose (newfp);
  1565. X    rename_file (newnewsrc, newsrc);
  1566. X
  1567. mark_group_read_done:
  1568. X    set_tin_uid_gid ();
  1569. }
  1570. X
  1571. X
  1572. void parse_seq(s)
  1573. X    char *s;
  1574. {
  1575. X    long low, high;
  1576. X    int i;
  1577. X
  1578. X    while (*s) {
  1579. X        while (*s && (*s < '0' || *s > '9'))
  1580. X            s++;
  1581. X
  1582. X        if (*s && *s >= '0' && *s <= '9') {
  1583. X            low = (long) atol (s);
  1584. X            while (*s && *s >= '0' && *s <= '9')
  1585. X                s++;
  1586. X            if (*s == '-') {
  1587. X                s++;
  1588. X                high = (long) atol (s);
  1589. X                while (*s && *s >= '0' && *s <= '9')
  1590. X                    s++;
  1591. X            }  else
  1592. X                high = low;
  1593. X
  1594. X            for (i = 0; i < top; i++)
  1595. X                if (arts[i].artnum >= low && arts[i].artnum <= high)
  1596. X                    arts[i].unread = ART_READ;
  1597. X        }
  1598. X    }
  1599. }
  1600. X
  1601. X
  1602. int parse_unread (s, groupnum)
  1603. X    char *s;
  1604. X    int groupnum;            /* index for group in active[] */
  1605. {
  1606. X    long low, high;
  1607. X    long last_high;
  1608. X    int sum = 0;
  1609. X    int gotone = FALSE;
  1610. X    int n;
  1611. X
  1612. /*
  1613. X *  Read the first range from the .newsrc sequencer information.  If the
  1614. X *  top of the first range is higher than what the active file claims is
  1615. X *  the bottom, use it as the new bottom instead
  1616. X */
  1617. X
  1618. X    high = 0;
  1619. X    if (*s) {
  1620. X        while (*s && (*s < '0' || *s > '9'))
  1621. X            s++;
  1622. X
  1623. X        if (*s && *s >= '0' && *s <= '9') {
  1624. X            low = (long) atol (s);
  1625. X            while (*s && *s >= '0' && *s <= '9')
  1626. X                s++;
  1627. X            if (*s == '-') {
  1628. X                s++;
  1629. X                high = (long) atol (s);
  1630. X                while (*s && *s >= '0' && *s <= '9')
  1631. X                    s++;
  1632. X            }  else
  1633. X                high = low;
  1634. X            gotone = TRUE;
  1635. X        }
  1636. X    }
  1637. X
  1638. X    /* Note that in the active file min will be one greater than max
  1639. X     * when there are no articles in the spool directory. ie., it is
  1640. X      * always true that "max - min + 1 = article count (including
  1641. X      * expired articles)"
  1642. X      */
  1643. X
  1644. X    if (high < active[groupnum].min - 1)
  1645. X        high = active[groupnum].min - 1;
  1646. X
  1647. X    while (*s) {
  1648. X        last_high = high;
  1649. X
  1650. X        while (*s && (*s < '0' || *s > '9'))
  1651. X            s++;
  1652. X
  1653. X        if (*s && *s >= '0' && *s <= '9') {
  1654. X            low = (long) atol (s);
  1655. X            while (*s && *s >= '0' && *s <= '9')
  1656. X                s++;
  1657. X            if (*s == '-') {
  1658. X                s++;
  1659. X                high = (long) atol (s);
  1660. X                while (*s && *s >= '0' && *s <= '9')
  1661. X                    s++;
  1662. X            }  else
  1663. X                high = low;
  1664. X
  1665. X            if (low > last_high)    /* otherwise seq out of order */
  1666. X                sum += (low - last_high) - 1;
  1667. X        }
  1668. X    }
  1669. X
  1670. X    if (gotone) {
  1671. X        if (active[groupnum].max > high)
  1672. X            sum += active[groupnum].max - high;
  1673. X        return sum;
  1674. X    }
  1675. X
  1676. X    n = (int) (active[groupnum].max - active[groupnum].min) + 1;
  1677. X    
  1678. X    if (n < 0)
  1679. X        return -1;
  1680. X    else
  1681. X        return (n);
  1682. }
  1683. X
  1684. X
  1685. int get_line_unread(group, groupnum)
  1686. X    char *group;
  1687. X    int groupnum;                /* index for group in active[] */
  1688. {
  1689. X    FILE *fp;
  1690. X    char buf[8192];
  1691. X    char *p;
  1692. X    int ret = -1;
  1693. X
  1694. X    if ((fp = fopen(newsrc, "r")) == NULL)
  1695. X        return -1;
  1696. X
  1697. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1698. X        p = buf;
  1699. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1700. X            p++;
  1701. X        *p++ = '\0';
  1702. X        
  1703. X        if (strcmp (buf, group) != 0)
  1704. X            continue;
  1705. X            
  1706. X        ret = parse_unread (p, groupnum);
  1707. X        break;
  1708. X    }
  1709. X
  1710. X    fclose (fp);
  1711. X    return ret;
  1712. }
  1713. X
  1714. X
  1715. void print_seq (fp, groupnum)
  1716. X    FILE *fp;
  1717. X    int groupnum;            /* index into active[] for this group */
  1718. {
  1719. X    long int artnum, last_read, artmax;
  1720. X    int i;
  1721. X    int flag = FALSE;
  1722. X    
  1723. X    assert(top >= 0);
  1724. X
  1725. X      /*
  1726. X       *  sort into the same order as in the spool area for writing
  1727. X       *  read article numbers to ~/.newsrc
  1728. X       */
  1729. X     if (top > 0)
  1730. X         qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  1731. X  
  1732. X     /*
  1733. X      * Note that killed and expired articles do not appear in arts[].
  1734. X      * So, even if top is 0 there may be sequencer info to output.
  1735. X     */
  1736. X     if (top > 0 && arts[top-1].artnum > active[groupnum].max)
  1737. X         artmax = arts[top-1].artnum;
  1738. X     else
  1739. X         artmax = active[groupnum].max;
  1740. X     for (artnum=1, i=0; artnum <= artmax; ++artnum, ++i) {
  1741. X         assert(i<=top);
  1742. X         if (i==top || arts[i].unread == ART_READ || artnum != arts[i].artnum) {
  1743. X              if (flag)
  1744. X                  fprintf(fp, ",");
  1745. X              else
  1746. X                  flag = TRUE;
  1747. X             fprintf (fp, "%ld", artnum);
  1748. X             while (i < top && arts[i].unread == ART_READ)
  1749. X                 ++i;
  1750. X             last_read = (i<top ? arts[i].artnum - 1 : artmax);
  1751. X             if (last_read != artnum) {
  1752. X                 fprintf(fp, "-%ld", last_read);
  1753. X              }
  1754. X
  1755. X             assert(i <= top);
  1756. X             if (i == top)
  1757. X                 break;
  1758. X             artnum = arts[i].artnum;
  1759. X          }
  1760. X      }
  1761. X  
  1762. X      fflush (fp);
  1763. X     if (top == 0)
  1764. X         return;
  1765. X
  1766. X    /*
  1767. X     *  resort into required sort order
  1768. X     */
  1769. X    switch (sort_art_type) {
  1770. X        case SORT_BY_NOTHING:        /* already sorted above */
  1771. X            break;
  1772. X        case SORT_BY_SUBJ_DESCEND:
  1773. X        case SORT_BY_SUBJ_ASCEND:
  1774. X            qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
  1775. X            break;
  1776. X        case SORT_BY_FROM_DESCEND:
  1777. X        case SORT_BY_FROM_ASCEND:
  1778. X            qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
  1779. X            break;
  1780. X        case SORT_BY_DATE_DESCEND:
  1781. X        case SORT_BY_DATE_ASCEND:
  1782. X            qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
  1783. X            break;
  1784. X    }
  1785. }
  1786. X
  1787. /*
  1788. X *  rewrite .newsrc and position group at specifed position
  1789. X */
  1790. X
  1791. int pos_group_in_newsrc (group, pos)
  1792. X    char *group;
  1793. X    int pos;
  1794. {
  1795. X    char sub[1024];
  1796. X    char unsub[1024];
  1797. X    char buf[1024];
  1798. X    char newsgroup[1024];
  1799. X    extern int cur_groupnum;
  1800. X    FILE *fp_in, *fp_out;
  1801. X    FILE *fp_sub, *fp_unsub;
  1802. X    int repositioned = FALSE;
  1803. X    int subscribed_pos = 1;
  1804. X    int group_len;
  1805. X    int option_line = FALSE;
  1806. X    int ret_code = FALSE;
  1807. X
  1808. X    set_real_uid_gid ();
  1809. X    
  1810. X    if ((fp_in = fopen (newsrc, "r")) == NULL) {
  1811. X        goto rewrite_group_done;
  1812. X    }
  1813. X    if ((fp_out = fopen (newnewsrc, "w")) == NULL) {
  1814. X        goto rewrite_group_done;
  1815. X    }
  1816. X
  1817. X    sprintf (sub, "/tmp/.subrc.%d", process_id);
  1818. X    sprintf (unsub, "/tmp/.unsubrc.%d", process_id);
  1819. X
  1820. X    if ((fp_sub = fopen (sub, "w")) == NULL) {
  1821. X        goto rewrite_group_done;
  1822. X    }
  1823. X    if ((fp_unsub = fopen (unsub, "w")) == NULL) {
  1824. X        goto rewrite_group_done;
  1825. X    }
  1826. X
  1827. X    /*
  1828. X     *  split newsrc into subscribed and unsubscribed to files
  1829. X     */
  1830. X    group_len = strlen (group);
  1831. X
  1832. X    while (fgets (buf, sizeof (buf), fp_in) != NULL) {
  1833. X        if (strncmp (group, buf, group_len) == 0 && buf[group_len] == ':') {
  1834. X            my_strncpy (newsgroup, buf, LEN);
  1835. X        } else if (strchr (buf, ':') != NULL) {
  1836. X            fprintf (fp_sub, "%s", buf);
  1837. X        } else if (strchr (buf, '!') != NULL) {
  1838. X            fprintf (fp_unsub, "%s", buf);
  1839. X        } else {    /* options line at beginning of .newsrc */
  1840. X            fprintf (fp_sub, "%s", buf);
  1841. X            option_line = TRUE;
  1842. X        }
  1843. X    }
  1844. X
  1845. X    fclose (fp_in);
  1846. X    fclose (fp_sub);
  1847. X    fclose (fp_unsub);
  1848. X
  1849. X    /*
  1850. X     *  write subscribed groups & position group to newnewsrc
  1851. X     */
  1852. X    if ((fp_sub = fopen (sub, "r")) == NULL) {
  1853. X        unlink (sub);
  1854. X        goto rewrite_group_done;
  1855. X    }
  1856. X    while (fgets (buf, LEN, fp_sub) != NULL) {
  1857. X        if (option_line) {
  1858. X            if (strchr (buf, ':') == NULL && strchr (buf, '!') == NULL) {
  1859. X                fprintf (fp_out, "%s", buf);
  1860. X                continue;
  1861. X            } else {
  1862. X                option_line = FALSE;
  1863. X            }
  1864. X        }
  1865. X
  1866. X        if (pos == subscribed_pos) {
  1867. X            fprintf (fp_out, "%s\n", newsgroup);
  1868. X            repositioned = TRUE;
  1869. X        }
  1870. X        
  1871. X        fprintf (fp_out, "%s", buf);
  1872. X
  1873. X        subscribed_pos++;
  1874. X    }
  1875. X    if (! repositioned) {
  1876. X        fprintf (fp_out, "%s\n", newsgroup);
  1877. X        repositioned = TRUE;
  1878. X    }
  1879. X    
  1880. X    fclose (fp_sub);
  1881. X     unlink (sub);
  1882. X
  1883. X    /*
  1884. X     *  write unsubscribed groups to newnewsrc
  1885. X     */
  1886. X    if ((fp_unsub = fopen (unsub, "r")) == NULL) {
  1887. X        unlink (unsub);
  1888. X        goto rewrite_group_done;
  1889. X    }
  1890. X    while (fgets (buf, LEN, fp_unsub) != NULL) {
  1891. X        fprintf (fp_out, "%s", buf);
  1892. X    }
  1893. X
  1894. X    fclose (fp_unsub);
  1895. X    unlink (unsub);
  1896. X    fclose (fp_out);
  1897. X
  1898. X    if (repositioned) {
  1899. X        cur_groupnum = pos;
  1900. X        rename_file (newnewsrc, newsrc);
  1901. X        ret_code = TRUE;
  1902. X    }
  1903. X
  1904. rewrite_group_done:
  1905. X    set_tin_uid_gid ();
  1906. X    return ret_code;
  1907. }
  1908. X
  1909. /*
  1910. X *  mark all orther Xref: articles as read when one article read
  1911. X *  Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
  1912. X */
  1913. void mark_all_xref_read (xref_line)
  1914. X    char *xref_line; 
  1915. {
  1916. /*
  1917. X    char group[LEN];
  1918. X    long artnum;
  1919. */    
  1920. X    if (xref_line == (char *) 0) {
  1921. X        return;
  1922. X    }
  1923. X
  1924. X    /*
  1925. X     *  check sitename macthes nodename of current machine
  1926. X     */
  1927. X
  1928. X    /*
  1929. X     *  tokenize each pair and update that newsgroup if it
  1930. X     *  is in users my_group[].
  1931. X     */
  1932. X     
  1933. }
  1934. SHAR_EOF
  1935. chmod 0600 newsrc.c ||
  1936. echo 'restore of newsrc.c failed'
  1937. Wc_c="`wc -c < 'newsrc.c'`"
  1938. test 21037 -eq "$Wc_c" ||
  1939.     echo 'newsrc.c: original size 21037, current size' "$Wc_c"
  1940. rm -f _shar_wnt_.tmp
  1941. fi
  1942. # ============= open.c ==============
  1943. if test -f 'open.c' -a X"$1" != X"-c"; then
  1944.     echo 'x - skipping open.c (File already exists)'
  1945.     rm -f _shar_wnt_.tmp
  1946. else
  1947. > _shar_wnt_.tmp
  1948. echo 'x - extracting open.c (Text)'
  1949. sed 's/^X//' << 'SHAR_EOF' > 'open.c' &&
  1950. /*
  1951. X *  Project   : tin - a threaded Netnews reader
  1952. X *  Module    : open.c
  1953. X *  Author    : I.Lea & R.Skrenta
  1954. X *  Created   : 01-04-91
  1955. X *  Updated   : 19-03-92
  1956. X *  Notes     : reads news locally (ie. /usr/spool/news) or via NNTP
  1957. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  1958. X *              You may  freely  copy or  redistribute  this software,
  1959. X *              so  long as there is no profit made from its use, sale
  1960. X *              trade or  reproduction.  You may not change this copy-
  1961. X *              right notice, and it must be included in any copy made
  1962. X */
  1963. X
  1964. #include    "tin.h"
  1965. #ifdef NNTP_ABLE
  1966. #    include    "nntp.h"
  1967. #endif
  1968. X
  1969. /*
  1970. X * Directory handling code - Hopefully one of these is right for you. 
  1971. X */
  1972. #ifdef BSD
  1973. #    ifdef sinix
  1974. #        include <dir.h>
  1975. #    else
  1976. #        include <sys/dir.h>
  1977. #    endif
  1978. #    define        DIR_BUF        struct direct
  1979. #    define        D_LENGTH    d_namlen
  1980. #endif
  1981. #ifdef M_XENIX
  1982. #    include <sys/ndir.h>
  1983. #    define        DIR_BUF        struct direct
  1984. #    define        D_LENGTH    d_namlen
  1985. #endif
  1986. #ifndef DIR_BUF
  1987. #    include    <dirent.h>
  1988. #    define        DIR_BUF        struct dirent
  1989. #    define        D_LENGTH    d_reclen
  1990. #endif
  1991. X
  1992. int nntp_codeno = 0;
  1993. X
  1994. #ifdef NNTP_ABLE
  1995. int compiled_with_nntp = TRUE;        /* used in mail_bug_report() info */
  1996. #else
  1997. int compiled_with_nntp = FALSE;
  1998. #endif
  1999. X
  2000. #ifdef NO_POSTING
  2001. int    can_post = FALSE;
  2002. #else
  2003. int    can_post = TRUE;
  2004. #endif
  2005. X
  2006. char server_name[LEN];
  2007. X
  2008. X
  2009. char *is_remote ()
  2010. {
  2011. X    server_name[0] = '\0';
  2012. X    
  2013. #ifdef NNTP_ABLE
  2014. X    if (read_news_via_nntp) {
  2015. X        if (nntp_server[0]) {
  2016. X            sprintf (server_name, " (%s)", nntp_server);
  2017. X        } else {
  2018. X            if (getserverbyfile (NNTP_SERVER_FILE)) {
  2019. X                sprintf (server_name, " (%s)", getserverbyfile (NNTP_SERVER_FILE));
  2020. X            } else {
  2021. X                strcpy (server_name, " (NO SERVER)");
  2022. X            }
  2023. X        }
  2024. X    }
  2025. #endif
  2026. X
  2027. X    return (server_name);
  2028. }
  2029. X
  2030. X
  2031. void nntp_startup ()
  2032. {
  2033. #ifdef NNTP_ABLE    
  2034. X    char *server;
  2035. X    int ret;
  2036. X
  2037. X    if (read_news_via_nntp) {
  2038. X        debug_nntp ("nntp_startup", "BEGIN");
  2039. X         
  2040. X        if (nntp_server[0]) {
  2041. X            server = nntp_server;
  2042. X        } else {
  2043. X            server = getserverbyfile (NNTP_SERVER_FILE);
  2044. X        }
  2045. X        if (server == (char *) 0) {
  2046. X            error_message (txt_cannot_get_nntp_server_name, "");
  2047. X            error_message (txt_server_name_in_file_env_var, NNTP_SERVER_FILE);
  2048. X            exit(1);
  2049. X        }
  2050. X
  2051. X        if (update == FALSE) {
  2052. X            sprintf (msg, txt_connecting, server);
  2053. X            wait_message (msg);
  2054. X        }
  2055. X        
  2056. X        debug_nntp ("nntp_startup", server);
  2057. X
  2058. X        ret = server_init (server);
  2059. X        if (update == FALSE) {
  2060. X            putchar ('\n');
  2061. X        }
  2062. /*
  2063. X        handle_server_response (ret, server);
  2064. */
  2065. X
  2066. X        debug_nntp_respcode (ret);
  2067. X
  2068. X        switch (ret) {
  2069. X        case OK_CANPOST:
  2070. #ifndef NO_POSTING        
  2071. X            can_post = TRUE;
  2072. #endif            
  2073. X            break;
  2074. X
  2075. X        case OK_NOPOST:
  2076. X            can_post = FALSE;
  2077. X            break;    
  2078. X
  2079. X        case -1:
  2080. X            error_message (txt_failed_to_connect_to_server, server);
  2081. X            exit (1);
  2082. X
  2083. X        default:
  2084. /*            error_message (txt_rejected_by_nntpserver, ret);
  2085. */
  2086. X            error_message ("tin: %s", nntp_respcode (ret));
  2087. X            exit (1);
  2088. X        }
  2089. X    }
  2090. #endif    
  2091. }
  2092. X
  2093. X
  2094. void nntp_finish ()
  2095. {
  2096. #ifdef NNTP_ABLE
  2097. X    if (read_news_via_nntp) {
  2098. X        debug_nntp ("nntp_finish", "END");
  2099. X        close_server ();
  2100. X    }
  2101. #endif    
  2102. }
  2103. X
  2104. X
  2105. FILE *open_active_fp ()
  2106. {
  2107. X    if (read_news_via_nntp) {
  2108. #ifdef NNTP_ABLE
  2109. X        put_server ("list");
  2110. X        if (get_respcode () != OK_GROUPS) {
  2111. X            debug_nntp ("open_active_fp", "NOT_OK");
  2112. X            return (FILE *) 0;
  2113. X        }
  2114. X        debug_nntp ("open_active_fp", "OK");
  2115. X        return nntp_to_fp ();
  2116. #else
  2117. X        return (FILE *) 0;
  2118. #endif        
  2119. X    } else {
  2120. X        return fopen (active_file, "r");
  2121. X    }
  2122. }
  2123. X
  2124. X
  2125. FILE *open_subscription_fp ()
  2126. {
  2127. X    if (read_news_via_nntp) {
  2128. #ifdef NNTP_ABLE
  2129. X        put_server ("list subscriptions");
  2130. X        if (get_respcode () != OK_GROUPS) {
  2131. X            debug_nntp ("open_subscription_fp", "NOT_OK");
  2132. X            return (FILE *) 0;
  2133. X        }
  2134. X        debug_nntp ("open_subscription_fp", "OK");
  2135. X        return nntp_to_fp ();
  2136. #else
  2137. X        return (FILE *) 0;
  2138. #endif        
  2139. X    } else {
  2140. X        return fopen (subscriptions_file, "r");
  2141. X    }
  2142. }
  2143. X
  2144. X
  2145. FILE *open_index_fp (group_name)
  2146. X    char *group_name;
  2147. {
  2148. #ifdef NNTP_ABLE
  2149. X    char line[NNTP_STRLEN];
  2150. #endif
  2151. X    extern char index_file[];
  2152. X    
  2153. X    find_index_file (group_name);
  2154. X    
  2155. #ifdef NNTP_XINDEX
  2156. X    if (read_news_via_nntp) {
  2157. X        sprintf (line, "xindex %s", group_name);
  2158. X        put_server (line);
  2159. X        if (get_respcode () != OK_XINDEX) {
  2160. X            debug_nntp ("open_index_fp", "NOT_OK");
  2161. X            return (FILE *) 0;
  2162. X        }
  2163. X        debug_nntp ("open_index_fp", "OK");
  2164. X        return nntp_to_fp ();
  2165. X    } else {
  2166. #endif    
  2167. X        return fopen (index_file, "r");
  2168. #ifdef NNTP_XINDEX
  2169. X    }
  2170. #endif    
  2171. }
  2172. X
  2173. X
  2174. FILE *open_art_fp (group_path, art)
  2175. X    char *group_path;
  2176. X    long art;
  2177. {
  2178. X    char buf[LEN];
  2179. X    int respcode;
  2180. X    struct stat sb;
  2181. X    extern long note_size;
  2182. X
  2183. X    if (read_news_via_nntp) {
  2184. #ifdef NNTP_ABLE
  2185. X        sprintf (buf, "article %ld", art);
  2186. X
  2187. X        debug_nntp ("open_art_fp", buf);
  2188. X        
  2189. X        put_server (buf);
  2190. X        if ((respcode = get_respcode ()) != OK_ARTICLE) {
  2191. X            error_message ("%s", nntp_respcode (respcode));
  2192. X            debug_nntp ("open_art_fp", buf);
  2193. X            return (FILE *) 0;
  2194. X        }
  2195. X
  2196. X        debug_nntp ("open_art_fp", "OK");
  2197. X
  2198. X        return nntp_to_fp ();
  2199. #else
  2200. X        return (FILE *) 0;
  2201. #endif
  2202. X    } else {
  2203. X        sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  2204. X
  2205. X        if (stat (buf, &sb) < 0) {
  2206. X            note_size = 0;
  2207. X        } else {
  2208. X            note_size = sb.st_size;
  2209. X        }
  2210. X        return fopen (buf, "r");
  2211. X    }
  2212. }
  2213. X
  2214. X
  2215. int open_header_fd (group_path, art)
  2216. X    char *group_path;
  2217. X    long art;
  2218. {
  2219. X    char buf[LEN];
  2220. X    
  2221. X    if (read_news_via_nntp) {
  2222. #ifdef NNTP_ABLE    
  2223. X        sprintf(buf, "head %ld", art);
  2224. X        
  2225. X        debug_nntp ("open_header_fd", buf);
  2226. X
  2227. X        put_server (buf);
  2228. X        if (get_respcode () != OK_HEAD) {
  2229. X            debug_nntp ("open_header_fd", "NOT_OK_HEAD");
  2230. X            return -1;
  2231. X        }
  2232. X
  2233. X        debug_nntp ("open_header_fd", "OK_HEAD");
  2234. X
  2235. X        return nntp_to_fd ();
  2236. #else
  2237. X        return -1;
  2238. #endif        
  2239. X    } else {
  2240. X        sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  2241. X        return open (buf, 0);
  2242. X    }
  2243. }
  2244. X
  2245. /*
  2246. X *  Longword comparison routine for the qsort()
  2247. X */
  2248. X
  2249. int base_comp (p1, p2)
  2250. X    char *p1;
  2251. X    char *p2;
  2252. {
  2253. X    long *a = (long *) p1;
  2254. X    long *b = (long *) p2;
  2255. X
  2256. X    if (*a < *b)
  2257. X        return -1;
  2258. X    if (*a > *b)
  2259. X        return 1;
  2260. X    return 0;
  2261. }
  2262. X
  2263. X
  2264. /*
  2265. X *  Read the article numbers existing in a group's spool directory
  2266. X *  into base[] and sort them.  top_base is one past top.
  2267. X */
  2268. X
  2269. void setup_base (group, group_path)
  2270. X    char *group;
  2271. X    char *group_path;
  2272. {
  2273. X    char buf[LEN];
  2274. #ifdef NNTP_ABLE
  2275. X    char line[NNTP_STRLEN];
  2276. #endif
  2277. X    DIR *d;
  2278. X    DIR_BUF *e;
  2279. X    long art, start, last, dummy, count;
  2280. X
  2281. X    top_base = 0;
  2282. X
  2283. X    if (read_news_via_nntp) {
  2284. #ifdef NNTP_ABLE
  2285. X        sprintf (buf, "group %s", group);
  2286. X
  2287. X        debug_nntp ("setup_base", buf);
  2288. X        
  2289. X        put_server (buf);
  2290. X
  2291. X        if (get_server (line, NNTP_STRLEN) == -1) {
  2292. X            error_message (txt_connection_to_server_broken, "");
  2293. X            tin_done (1);
  2294. X        }
  2295. X
  2296. X        if (atoi(line) != OK_GROUP) {
  2297. X            debug_nntp ("setup_base", "NOT_OK");
  2298. X            return;
  2299. X        }
  2300. X
  2301. X        debug_nntp ("setup_base", line);
  2302. X
  2303. X        sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last);
  2304. X        if (last - count > start) {
  2305. X            start = last - count;
  2306. X        }
  2307. X
  2308. X        while (start <= last) {
  2309. X            if (top_base >= max_art) {
  2310. X                expand_art();
  2311. X            }
  2312. X            base[top_base++] = start++;
  2313. X        }
  2314. #else
  2315. X        return; 
  2316. #endif
  2317. X    } else {
  2318. X        sprintf (buf, "%s/%s", SPOOLDIR, group_path);
  2319. X
  2320. X        if (access (buf, 4) != 0) {
  2321. X            return;
  2322. X        }
  2323. X
  2324. X        d = opendir (buf);
  2325. X        if (d != NULL) {
  2326. X            while ((e = readdir (d)) != NULL) {
  2327. X                art = my_atol (e->d_name, (int) e->D_LENGTH);
  2328. X                if (art >= 0) {
  2329. X                    if (top_base >= max_art)
  2330. X                        expand_art ();
  2331. X                    base[top_base++] = art;
  2332. X                }
  2333. X            }
  2334. X            closedir (d);
  2335. X            qsort ((char *) base, top_base, sizeof (long), base_comp);
  2336. X        }
  2337. X    }
  2338. }
  2339. X
  2340. /*
  2341. X *  get_respcode
  2342. X *  get a response code from the server and return it to the caller
  2343. X */
  2344. X
  2345. int get_respcode ()
  2346. {
  2347. #ifdef NNTP_ABLE
  2348. X    char line[NNTP_STRLEN];
  2349. X
  2350. X    if (get_server (line, NNTP_STRLEN) == -1) {
  2351. X        error_message (txt_connection_to_server_broken, "");
  2352. X        tin_done (1);
  2353. X    }
  2354. X
  2355. X    debug_nntp_respcode (atoi (line));
  2356. X    
  2357. X    return atoi (line);
  2358. #else
  2359. X    return (0);
  2360. #endif
  2361. }
  2362. X
  2363. X
  2364. int stuff_nntp (fnam)
  2365. X    char *fnam;
  2366. {
  2367. #ifdef NNTP_ABLE
  2368. X    FILE *fp;
  2369. X    char line[NNTP_STRLEN];
  2370. X    extern char *mktemp ();
  2371. X    struct stat sb;
  2372. X    extern long note_size;
  2373. X
  2374. X    strcpy (fnam, "/tmp/tin_nntpXXXXXX");
  2375. X    mktemp (fnam);
  2376. X
  2377. X    if ((fp = fopen (fnam, "w")) == NULL) {
  2378. X        error_message (txt_stuff_nntp_cannot_open, fnam);
  2379. X        return FALSE;
  2380. X    }
  2381. X
  2382. X    while (1) {
  2383. X        if (get_server (line, NNTP_STRLEN) == -1) {
  2384. X            error_message (txt_connection_to_server_broken, "");
  2385. X            tin_done (1);
  2386. X        }
  2387. X
  2388. X        debug_nntp ("stuff_nntp", line);
  2389. X        
  2390. X        if (strcmp (line, ".") == 0)
  2391. X            break;            /* end of text */
  2392. X        strcat (line, "\n");
  2393. X        if (line[0] == '.')        /* reduce leading .'s */
  2394. X            fputs (&line[1], fp);
  2395. X        else
  2396. X            fputs (line, fp);
  2397. X    }
  2398. X    fclose (fp);
  2399. X
  2400. X    if (stat (fnam, &sb) < 0)
  2401. X        note_size = 0;
  2402. X    else
  2403. X        note_size = sb.st_size;
  2404. X
  2405. X    return TRUE;
  2406. #else
  2407. X    return TRUE;
  2408. #endif
  2409. }
  2410. X
  2411. X
  2412. FILE *nntp_to_fp ()
  2413. {
  2414. #ifdef NNTP_ABLE
  2415. X    char fnam[LEN];
  2416. X    FILE *fp = NULL;
  2417. X    
  2418. X    if (! stuff_nntp (fnam)) {
  2419. X        debug_nntp ("nntp_to_fp", "! stuff_nntp()");
  2420. X        return NULL;
  2421. X    }
  2422. X
  2423. X    if ((fp = fopen (fnam, "r")) == NULL) {
  2424. X        error_message (txt_nntp_to_fp_cannot_reopen, fnam);
  2425. X        return NULL;
  2426. X    }
  2427. X    
  2428. X    unlink (fnam);
  2429. X    return fp;
  2430. #else
  2431. X    return NULL;
  2432. #endif
  2433. }
  2434. X
  2435. X
  2436. int nntp_to_fd ()
  2437. {
  2438. #ifdef NNTP_ABLE
  2439. X    char fnam[LEN];
  2440. X    static int fd = -1;
  2441. X
  2442. X    if (fd != -1) {
  2443. X        debug_nntp ("nntp_to_fd", "fd != -1");
  2444. X        close (fd);
  2445. X    }
  2446. X    
  2447. X    if (! stuff_nntp (fnam)) {
  2448. X        debug_nntp ("nntp_to_fd", "! stuff_nntp()");
  2449. X        return -1;
  2450. X    }
  2451. X
  2452. X    if ((fd = open (fnam, 0)) == -1) {
  2453. X        error_message (txt_nntp_to_fd_cannot_reopen, fnam);
  2454. X        return -1;
  2455. X    }
  2456. X    
  2457. X    unlink (fnam);
  2458. X    return fd;
  2459. #else
  2460. X    return -1;
  2461. #endif
  2462. }
  2463. X
  2464. /*
  2465. X * Log user info to local file or NNTP logfile
  2466. X */
  2467. X
  2468. void log_user ()
  2469. {
  2470. #ifdef LOG_USER
  2471. X    char buf[32], *ptr;
  2472. X    char line[NNTP_STRLEN];
  2473. X    FILE *fp;
  2474. X    long epoch;
  2475. X    extern struct passwd *myentry;
  2476. X
  2477. X    my_strncpy (buf, myentry->pw_gecos, sizeof (buf));
  2478. X
  2479. #ifdef NNTP_XUSER
  2480. X    if (read_news_via_nntp) {
  2481. X        if ((ptr = (char *) strchr(buf, ','))) {
  2482. X            *ptr = '\0';
  2483. X        }
  2484. X        sprintf (line, "xuser %s (%s)", myentry->pw_name, buf);
  2485. X
  2486. X        debug_nntp ("log_user", line);
  2487. X        
  2488. X        put_server (line);
  2489. X    } else {
  2490. #endif    
  2491. X        if ((fp = fopen (LOG_USER_FILE, "a+")) != NULL) {
  2492. X            time (&epoch);
  2493. X            fprintf (fp, "%s%d: %-32s (%-8s) %s", VERSION, PATCHLEVEL,
  2494. X                    buf, myentry->pw_name, ctime (&epoch));
  2495. X            fclose (fp);
  2496. X            chmod (LOG_USER_FILE, 0666);
  2497. X        }    
  2498. #ifdef NNTP_XUSER
  2499. X    }
  2500. #endif
  2501. #endif
  2502. }
  2503. X
  2504. /*
  2505. X * NNTP strings for get_respcode()
  2506. X */
  2507. X
  2508. char *nntp_respcode (respcode)
  2509. X    int respcode;
  2510. {
  2511. #ifdef NNTP_ABLE
  2512. X
  2513. X    static char *text;
  2514. X    
  2515. X    switch (respcode) {
  2516. X        case 0:
  2517. X            text = "";
  2518. X            break;
  2519. X        case INF_HELP:
  2520. X            text = "100  Help text on way";
  2521. X            break;
  2522. X        case INF_DEBUG:
  2523. X            text = "199  Debug output";
  2524. X            break;
  2525. X        case OK_CANPOST:
  2526. X            text = "200  Hello; you can post";
  2527. X            break;
  2528. X        case OK_NOPOST:
  2529. X            text = "201  Hello; you can't post";
  2530. X            break;
  2531. X        case OK_SLAVE:
  2532. X            text = "202  Slave status noted";
  2533. X            break;
  2534. X        case OK_GOODBYE:
  2535. X            text = "205  Closing connection";
  2536. X            break;
  2537. X        case OK_GROUP:
  2538. X            text = "211  Group selected";
  2539. X            break;
  2540. X        case OK_GROUPS:
  2541. X            text = "215  Newsgroups follow";
  2542. X            break;
  2543. X        case OK_XINDEX:
  2544. X            text = "218  Group index file follows";
  2545. X            break;
  2546. X        case OK_ARTICLE:
  2547. X            text = "220  Article (head & body) follows";
  2548. X            break;
  2549. X        case OK_HEAD:
  2550. X            text = "221  Head follows";
  2551. X            break;
  2552. X        case OK_BODY:
  2553. X            text = "222  Body follows";
  2554. X            break;
  2555. X        case OK_NOTEXT:
  2556. X            text = "223  No text sent -- stat, next, last";
  2557. X            break;
  2558. X        case OK_NEWNEWS:
  2559. X            text = "230  New articles by message-id follow";
  2560. X            break;
  2561. X        case OK_NEWGROUPS:
  2562. X            text = "231  New newsgroups follow";
  2563. X            break;
  2564. X        case OK_XFERED:
  2565. X            text = "235  Article transferred successfully";
  2566. X            break;
  2567. X        case OK_POSTED:
  2568. X            text = "240  Article posted successfully";
  2569. X            break;
  2570. X        case CONT_XFER:
  2571. X            text = "335  Continue to send article";
  2572. X            break;
  2573. X        case CONT_POST:
  2574. X            text = "340  Continue to post article";
  2575. X            break;
  2576. X        case ERR_GOODBYE:
  2577. X            text = "400  Have to hang up for some reason";
  2578. SHAR_EOF
  2579. true || echo 'restore of open.c failed'
  2580. fi
  2581. echo 'End of tin1.1 part 7'
  2582. echo 'File open.c is continued in part 8'
  2583. echo 8 > _shar_seq_.tmp
  2584. exit 0
  2585.  
  2586. --
  2587. NAME   Iain Lea 
  2588. EMAIL  iain%anl433.uucp@germany.eu.net
  2589. SNAIL  Siemens AG, ANL A433SZ, Gruendlacher Str. 248, 8510 Fuerth, Germany.
  2590. PHONE  +49-911-3089-407 (work) +49-911-331963 (home) +49-911-3089-290 (FAX)  
  2591. -- 
  2592.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2593.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2594.  Innere Medizin III                         
  2595.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2596. exit 0 # Just in case...
  2597.