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

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@Germany.EU.net (Iain Lea)
  3. Subject:  v31i010:  tin - threaded full screen newsreader v1.1 PL4, Part10/15
  4. Message-ID: <1992Jul7.181822.7725@sparky.imd.sterling.com>
  5. X-Md4-Signature: b096bd8401d054652e5b19cf0bd3153d
  6. Date: Tue, 7 Jul 1992 18:18:22 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: iain%anl433.uucp@Germany.EU.net (Iain Lea)
  10. Posting-number: Volume 31, Issue 10
  11. Archive-name: tin/part10
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 30, Issue 1-14
  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:  init.c newsrc.c nntplib.c
  22. # Wrapped by kent@sparky on Mon Jun 29 23:35:13 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 15)."'
  26. if test -f 'init.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'init.c'\"
  28. else
  29.   echo shar: Extracting \"'init.c'\" \(15082 characters\)
  30.   sed "s/^X//" >'init.c' <<'END_OF_FILE'
  31. X/*
  32. X *  Project   : tin - a threaded Netnews reader
  33. X *  Module    : init.c
  34. X *  Author    : I.Lea
  35. X *  Created   : 01-04-91
  36. X *  Updated   : 20-06-92
  37. X *  Notes     :
  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. Xchar rcdir[PATH_LEN];
  48. Xchar rcfile[PATH_LEN];
  49. Xchar indexdir[PATH_LEN];
  50. Xchar killfile[PATH_LEN];
  51. Xchar postfile[PATH_LEN];
  52. Xchar unthreadfile[PATH_LEN];
  53. Xchar cvers[LEN];
  54. Xchar nntp_server[LEN];
  55. Xchar active_file[PATH_LEN];
  56. Xchar newsgroups_file[PATH_LEN];
  57. Xchar subscriptions_file[PATH_LEN];
  58. Xchar homedir[PATH_LEN];
  59. Xchar userid[LEN];
  60. Xchar delgroups[LEN];
  61. Xchar default_maildir[PATH_LEN];            /* mailbox dir where = saves are stored */
  62. Xchar newsrc[PATH_LEN];
  63. Xchar newnewsrc[PATH_LEN];
  64. Xchar add_addr[LEN];            /* address to add to rR reply to author with mail */
  65. Xchar bug_addr[LEN];            /* address to add send bug reports to */
  66. Xchar txt_help_bug_report[LEN];    /* address to add send bug reports to */
  67. Xchar reply_to[LEN];            /* Reply-To: address */
  68. Xchar my_org[LEN];            /* Organization: */
  69. Xchar my_distribution[LEN];        /* Distribution: */
  70. Xchar default_select_pattern[LEN];
  71. Xchar default_sigfile[PATH_LEN];
  72. Xchar default_signature[PATH_LEN];
  73. Xchar default_shell_command[LEN];    /* offers user default choice */
  74. Xchar killsubj[LEN];            /* contains Subject:'s not to be shown */
  75. Xchar killfrom[LEN];            /* conatins From:'s not to be shown */
  76. Xchar page_header[LEN];        /* page header of pgm name and version */
  77. Xchar default_savedir[PATH_LEN];            /* directory to save articles to */
  78. Xchar spooldir[PATH_LEN];        /* directory where news is */
  79. Xchar spooldir_alias[PATH_LEN];        /* alias of spooldir being used */
  80. Xchar mail_news_user[LEN];    /* mail new news to this user address */
  81. Xchar mailer[PATH_LEN];            /* mail program */
  82. Xchar mailbox[PATH_LEN];            /* system mailbox for each user */
  83. Xchar printer[LEN];            /* printer program specified from tinrc */
  84. Xchar cmd_line_printer[LEN];    /* printer program specified on cmd line */
  85. Xchar article[PATH_LEN];            /* ~/.article file */
  86. Xchar dead_article[PATH_LEN];    /* ~/dead.article file */
  87. Xchar progname[PATH_LEN];        /* program name */
  88. Xchar redirect_output[LEN];    /* /dev/null or nothing if -D option */
  89. X
  90. Xint xindex_supported = FALSE;
  91. Xint xuser_supported = FALSE;
  92. Xint xspooldir_supported = FALSE;
  93. Xint NOTESLINES;                        /* set in set_win_size () */
  94. Xint RIGHT_POS;                        /* set in set_win_size () */
  95. Xint MORE_POS;                        /* set in set_win_size () */
  96. Xint confirm_action;
  97. Xint max_subj = 0;
  98. Xint max_from = 0;
  99. Xint max_active;
  100. Xint num_active;                        /* one past top of active */
  101. Xint group_top;                        /* one past top of my_group */
  102. Xint groupname_len = 0;                    /* one past top of my_group */
  103. Xint catchup = FALSE;                /* mark all arts read in all subscribed groups */
  104. Xint update_fork = FALSE;            /* update index files by forked tin -u */
  105. Xint verbose = FALSE;                /* update index files only mode */
  106. Xint start_line_offset;                /* used by invoke_editor for line no. */
  107. Xint inn_nntp_server = FALSE;            /* read news via INN NNTP */
  108. Xint read_news_via_nntp = FALSE;        /* read news locally or via NNTP */
  109. Xint local_index;                    /* do private indexing? */
  110. Xint max_art;
  111. Xint real_gid;
  112. Xint real_uid;
  113. Xint real_umask;
  114. Xint show_description;
  115. Xint start_editor_offset;
  116. Xint tin_uid;
  117. Xint tin_gid;
  118. Xint top = 0;
  119. Xint top_base;
  120. Xint check_any_unread = FALSE;
  121. Xint notify_new_groups = FALSE;
  122. Xint start_any_unread = FALSE;
  123. X
  124. Xint catchup_read_groups;    /* ask if read groups are to be marked read */
  125. Xint cmd_line;                /* batch / interactive mode */
  126. Xint created_rcdir;            /* checks if first time tin is started */
  127. Xint default_printer;        /* set to false if user give a printer with -p switch */
  128. Xint default_show_author;    /* show_author value from 'M' menu in tinrc */
  129. Xint draw_arrow_mark;        /* draw -> or highlighted bar */
  130. Xint full_page_scroll;        /* page half/full screen of articles/groups */
  131. Xint killed_articles;        /* killed / auto-selected hot articles */
  132. Xint mark_saved_read;        /* mark saved article/thread as read */
  133. Xint num_of_hot_arts;
  134. Xint num_of_killed_arts;
  135. Xint num_of_tagged_arts;
  136. Xint process_id;
  137. Xint pos_first_unread;        /* position cursor at first/last unread article */
  138. Xint post_proc_type;            /* type of post processing to be performed */
  139. Xint print_header;            /* print all of mail header or just Subject: & From lines */
  140. Xint save_archive_name;        /* save thread with name from Archive-name: field */
  141. Xint mail_news;                /* mail all arts to specified user */
  142. Xint save_news;                /* save all arts to savedir structure */
  143. Xint show_author;            /* show Subject & From or only Subject in group menu */
  144. Xint show_only_unread;        /* show only new/unread arts or all arts */
  145. Xint spooldir_is_active;            /* set TRUE if current spooldir is active news feed */
  146. Xint sort_art_type;            /* sort arts[] array by subject,from or date field */
  147. Xint thread_arts;            /* thread/unthread articles for viewing */
  148. Xint system_status;
  149. X
  150. X#ifdef INDEX_DAEMON
  151. Xint update = TRUE;                    /* update index files only mode */
  152. X#else
  153. Xint update = FALSE;                    /* update index files only mode */
  154. X#endif
  155. X
  156. Xstruct passwd *myentry;
  157. X
  158. X
  159. X/*
  160. X * Get users home directory, userid, and a bunch of other stuff!
  161. X */
  162. X
  163. Xvoid init_selfinfo ()
  164. X{
  165. X    extern char *getlogin ();
  166. X    extern struct passwd *getpwnam ();
  167. X    char nam[LEN];
  168. X    char *p;
  169. X    FILE *fp;
  170. X    struct stat sb;
  171. X
  172. X    process_id = getpid ();
  173. X    
  174. X    tin_uid = geteuid ();
  175. X    tin_gid = getegid ();
  176. X    real_uid = getuid ();
  177. X    real_gid = getgid ();
  178. X
  179. X    real_umask = umask (0);
  180. X    umask (real_umask);
  181. X    
  182. X#ifdef SVR4
  183. X    setlocale (LC_ALL, "");
  184. X#endif
  185. X        
  186. X    /*
  187. X     * we're setuid, so index in /usr/spool/news even if user root
  188. X     * This is quite essential if non local index files are 
  189. X     * to be updated during the night from crontab by root.
  190. X     */
  191. X    if (tin_uid != real_uid) {
  192. X        local_index = FALSE;
  193. X        set_real_uid_gid ();
  194. X
  195. X    } else {    /* index in users home directory ~/.tin/.index */
  196. X        local_index = TRUE;
  197. X    }
  198. X
  199. X    myentry = (struct passwd *) 0;
  200. X    if (((p = getlogin ()) != (char *) 0) && strlen (p)) {
  201. X        myentry = getpwnam (p);
  202. X    } else {
  203. X        myentry = getpwuid (getuid ());
  204. X    }
  205. X
  206. X    strcpy (userid, myentry->pw_name);
  207. X
  208. X    if ((p = (char *) getenv ("HOME")) != NULL) {
  209. X        strcpy (homedir, p);
  210. X    } else {
  211. X        strcpy (homedir, myentry->pw_dir);
  212. X    }
  213. X
  214. X    catchup_read_groups = FALSE;
  215. X    confirm_action = TRUE;
  216. X    created_rcdir = FALSE;
  217. X#ifdef USE_INVERSE_HACK
  218. X    inverse_okay = FALSE;
  219. X    draw_arrow_mark = TRUE;
  220. X#else
  221. X    draw_arrow_mark = FALSE;
  222. X#endif
  223. X    default_move_group = 0;
  224. X#ifdef BSD
  225. X    default_printer = TRUE;
  226. X#else    
  227. X    default_printer = FALSE;
  228. X#endif
  229. X    default_show_author = SHOW_FROM_NAME;
  230. X    full_page_scroll = TRUE;
  231. X    killed_articles = FALSE;
  232. X    mark_saved_read = TRUE;
  233. X    num_of_hot_arts = 0;
  234. X    num_of_killed_arts = 0;
  235. X    num_of_tagged_arts = 0;
  236. X    post_proc_type = POST_PROC_NONE;
  237. X    pos_first_unread = TRUE;
  238. X    print_header = FALSE;
  239. X    save_archive_name = TRUE;
  240. X    save_news = FALSE;
  241. X    show_only_unread = FALSE;
  242. X    show_description = TRUE;
  243. X    sort_art_type = SORT_BY_DATE_ASCEND;
  244. X    start_editor_offset = TRUE;
  245. X    thread_arts = TRUE;
  246. X    
  247. X    killsubj[0] = '\0';
  248. X    killfrom[0] = '\0';
  249. X    
  250. X    cmd_line_printer[0] = '\0';
  251. X    default_author_search[0] = '\0';
  252. X    default_goto_group[0] = '\0';
  253. X    default_group_search[0] = '\0';
  254. X    default_subject_search[0] = '\0';
  255. X    default_art_search[0] = '\0';
  256. X    default_crosspost_group[0] = '\0';
  257. X    default_mail_address[0] = '\0';
  258. X    default_pipe_command[0] = '\0';
  259. X    default_post_subject[0] = '\0';
  260. X    default_regex_pattern[0] = '\0';
  261. X    default_save_file[0] = '\0';
  262. X    default_select_pattern[0] = '\0';
  263. X    default_shell_command[0] = '\0';
  264. X    nntp_server[0] = '\0';
  265. X    proc_ch_default = 'n';
  266. X
  267. X    /*
  268. X     * set start spooldir to active newsfeed
  269. X     */
  270. X    strcpy (spooldir_alias, "news");
  271. X    strcpy (spooldir, SPOOLDIR);
  272. X
  273. X    set_tindir ();    
  274. X
  275. X    sprintf (active_file, "%s/active", LIBDIR);
  276. X    sprintf (article, "%s/.article", homedir);
  277. X    sprintf (dead_article, "%s/dead.article", homedir);
  278. X    sprintf (delgroups, "%s/.delgroups", homedir);
  279. X    sprintf (mailbox, "%s/%s", DEFAULT_MAILBOX, userid);
  280. X    sprintf (default_maildir, "%s/%s", homedir, DEFAULT_MAILDIR);
  281. X    sprintf (default_savedir, "%s/News", homedir);
  282. X    sprintf (default_sigfile, "%s/.Sig", homedir);
  283. X    sprintf (default_signature, "%s/.signature", homedir);
  284. X    sprintf (newsgroups_file, "%s/newsgroups", LIBDIR);
  285. X    sprintf (subscriptions_file, "%s/subscriptions", LIBDIR);
  286. X
  287. X    strcpy (mailer, get_val ("MAILER", DEFAULT_MAILER));
  288. X    strcpy (printer, DEFAULT_PRINTER);
  289. X    strcpy (spooldir, SPOOLDIR);
  290. X    strcpy (bug_addr, BUG_REPORT_ADDRESS);
  291. X    strcpy (redirect_output, "> /dev/null 2>&1");
  292. X
  293. X#ifdef INDEX_DAEMON
  294. X    /*
  295. X     * Check for lock file to stop multiple copies of tind running and
  296. X     * if it does not exist create it so this is the only copy running
  297. X     */
  298. X    if (stat (LOCK_FILE, &sb) == 0) {
  299. X        if ((fp = fopen (LOCK_FILE, "r")) != (FILE *) 0) {
  300. X            fgets (nam, sizeof (nam), fp);
  301. X            fclose (fp);
  302. X            fprintf(stderr, "%s: Already started pid=[%d] on %s", 
  303. X                progname, atoi(nam), nam+8);
  304. X            exit (1);
  305. X        }
  306. X    } else {
  307. X        {
  308. X            long epoch;
  309. X            
  310. X            if ((fp = fopen (LOCK_FILE, "w")) != (FILE *) 0) {
  311. X                time (&epoch);
  312. X                fprintf (fp, "%6d  %s", process_id, ctime (&epoch));
  313. X                fclose (fp);
  314. X                chmod (LOCK_FILE, 0600);
  315. X            }
  316. X        }    
  317. X    }
  318. X     
  319. X    strcpy (newsrc, active_file);    /* so that all groups are indexed */
  320. X    sprintf (indexdir, "%s/.index", spooldir);
  321. X
  322. X    if (stat (indexdir, &sb) == -1) {
  323. X        mkdir (indexdir, 0777);
  324. X    }
  325. X#else
  326. X    if (stat (rcdir, &sb) == -1) {
  327. X        created_rcdir = TRUE;
  328. X        mkdir (rcdir, 0755);
  329. X    }
  330. X    if (tin_uid != real_uid) {
  331. X        sprintf (indexdir, "%s/.index", spooldir);
  332. X
  333. X        set_tin_uid_gid ();
  334. X        if (stat (indexdir, &sb) == -1) {
  335. X            mkdir (indexdir, 0777);
  336. X        }
  337. X        set_real_uid_gid ();
  338. X    } else if (stat (indexdir, &sb) == -1) {
  339. X        mkdir (indexdir, 0755);
  340. X    }
  341. X    if (stat (postfile, &sb) == -1) {
  342. X        if ((fp = fopen (postfile, "w")) != NULL) {
  343. X            fclose (fp);
  344. X        }
  345. X    }
  346. X    if (stat (unthreadfile, &sb) == -1) {
  347. X        if ((fp = fopen (unthreadfile, "w")) != NULL) {
  348. X            fclose (fp);
  349. X        }
  350. X    }
  351. X
  352. X    read_rcfile ();
  353. X
  354. X    show_author = default_show_author;
  355. X
  356. X#endif /* INDEX_DAEMON */    
  357. X
  358. X    if (stat (active_file, &sb) >= 0)
  359. X        goto got_active;
  360. X
  361. X    /*
  362. X     *  I hate forgetting to define LIBDIR correctly.  Guess a couple
  363. X     *  of the likely places if it's not where LIBDIR says it is.
  364. X     */
  365. X
  366. X    strcpy (active_file, "/usr/lib/news/active");
  367. X    if (stat (active_file, &sb) >= 0)
  368. X        goto got_active;
  369. X
  370. X    strcpy (active_file, "/usr/local/lib/news/active");
  371. X    if (stat (active_file, &sb) >= 0)
  372. X        goto got_active;
  373. X
  374. X    strcpy (active_file, "/usr/public/lib/news/active");
  375. X    if (stat (active_file, &sb) >= 0)
  376. X        goto got_active;
  377. X
  378. X    /*
  379. X     *  Oh well. Revert to what LIBDIR says it is to produce a useful
  380. X     *  error message when read_active_file () fails later.
  381. X     */
  382. X
  383. X    sprintf (active_file, "%s/active", LIBDIR);
  384. X
  385. Xgot_active:
  386. X
  387. X    /*
  388. X     *  check enviroment for ORGANIZATION / NEWSORG
  389. X     */
  390. X    my_org[0] = '\0';
  391. X#ifdef apollo
  392. X    if ((p = (char *) getenv ("NEWSORG")) != NULL) {
  393. X#else    
  394. X    if ((p = (char *) getenv ("ORGANIZATION")) != NULL) {
  395. X#endif
  396. X        my_strncpy (my_org, p, sizeof (my_org));
  397. X        goto got_org;
  398. X    }
  399. X
  400. X    /*
  401. X     *  check ~/.tin/organization for organization
  402. X     */
  403. X    sprintf (nam, "%s/organization", rcdir);
  404. X    fp = fopen (nam, "r");
  405. X
  406. X    /*
  407. X     *  check LIBDIR/organization for system wide organization
  408. X     */
  409. X    if (fp == NULL) {
  410. X        sprintf (nam, "%s/organization", LIBDIR);
  411. X        fp = fopen (nam, "r");
  412. X    }
  413. X
  414. X    if (fp == NULL) {
  415. X        sprintf (nam, "/usr/lib/news/organization");
  416. X        fp = fopen (nam, "r");
  417. X    }
  418. X
  419. X    if (fp == NULL) {
  420. X        sprintf (nam, "/usr/local/lib/news/organization");
  421. X        fp = fopen (nam, "r");
  422. X    }
  423. X
  424. X    if (fp == NULL) {
  425. X        sprintf (nam, "/usr/public/lib/news/organization");
  426. X        fp = fopen (nam, "r");
  427. X    }
  428. X
  429. X    if (fp == NULL) {
  430. X        sprintf (nam, "/etc/organization");
  431. X        fp = fopen (nam, "r");
  432. X    }
  433. X
  434. X    if (fp != NULL) {
  435. X        if (fgets (my_org, sizeof (my_org), fp) != NULL) {
  436. X            for (p = my_org; *p && *p != '\n'; p++)
  437. X                continue;
  438. X            *p = '\0';
  439. X        }
  440. X        fclose (fp);
  441. X    }
  442. X
  443. Xgot_org:;
  444. X
  445. X    /*
  446. X     *  check enviroment for REPLYTO
  447. X     */
  448. X    reply_to[0] = '\0';
  449. X    if ((p = (char *) getenv ("REPLYTO")) != NULL) {
  450. X        my_strncpy (reply_to, p, sizeof (reply_to));
  451. X        goto got_reply;
  452. X    }
  453. X
  454. X    sprintf (nam, "%s/replyto", rcdir);
  455. X    if ((fp = fopen (nam, "r")) != NULL) {
  456. X        if (fgets (reply_to, sizeof (reply_to), fp) != NULL) {
  457. X            reply_to[strlen (reply_to)-1] = '\0';
  458. X        }
  459. X        fclose (fp);
  460. X    }
  461. X
  462. Xgot_reply:;
  463. X
  464. X    /*
  465. X     *  check enviroment for DISTRIBUTION
  466. X     */
  467. X    my_distribution[0] = '\0';
  468. X    if ((p = (char *) getenv ("DISTRIBUTION")) != NULL) {
  469. X        my_strncpy (my_distribution, p, sizeof (my_distribution));
  470. X    }
  471. X
  472. X    /*
  473. X     *  check enviroment for ADD_ADDRESS
  474. X      */
  475. X    add_addr[0] = '\0';
  476. X    if ((p = (char *) getenv ("ADD_ADDRESS")) != NULL) {
  477. X        my_strncpy (add_addr, p, sizeof (add_addr));
  478. X        goto got_add_addr;
  479. X    }
  480. X
  481. X    sprintf (nam, "%s/add_address", rcdir);
  482. X    if ((fp = fopen (nam, "r")) != NULL) {
  483. X        if (fgets (add_addr, sizeof (add_addr), fp) != NULL) {
  484. X            add_addr[strlen (add_addr)-1] = '\0';
  485. X        }
  486. X        fclose (fp);
  487. X    }
  488. X
  489. Xgot_add_addr:;
  490. X
  491. X    /*
  492. X     *  check enviroment for BUG_ADDRESS
  493. X     */
  494. X    if ((p = (char *) getenv ("BUG_ADDRESS")) != NULL) {
  495. X        my_strncpy (bug_addr, p, sizeof (bug_addr));
  496. X        goto got_bug_addr;
  497. X    }
  498. X
  499. X    sprintf (nam, "%s/bug_address", rcdir);
  500. X    if ((fp = fopen (nam, "r")) != NULL) {
  501. X        if (fgets (bug_addr, sizeof (bug_addr), fp) != NULL) {
  502. X            bug_addr[strlen (bug_addr)-1] = '\0';
  503. X        }
  504. X        fclose (fp);
  505. X    }
  506. X
  507. Xgot_bug_addr:;
  508. X    sprintf (txt_help_bug_report, txt_help_bug, bug_addr);
  509. X}
  510. X
  511. X/*
  512. X * Set up ~/.tin directory & support files depending on where the news
  513. X * is being read from (ie. active news / CD-ROM spooldir).  Note that
  514. X * any control files which may be specific to a given spooldir (various
  515. X * CD issues versus live news) should be under the spooldir_alias 
  516. X * subdirectory also.
  517. X */
  518. Xvoid set_tindir ()
  519. X{
  520. X    struct stat sb;
  521. X    
  522. X    if (strcmp (spooldir_alias, "news") != 0) {
  523. X        sprintf (rcdir,  "%s/%s", get_val ("TINDIR", homedir), RCDIR);
  524. X        /*
  525. X         * Create directories
  526. X         */
  527. X        if (stat (rcdir, &sb) == -1) {
  528. X            mkdir (rcdir, 0755);
  529. X        }
  530. X        sprintf (rcdir, "%s/%s", rcdir, spooldir_alias); 
  531. X        if (stat (rcdir, &sb) == -1) {
  532. X            created_rcdir = TRUE;
  533. X            mkdir (rcdir, 0755);
  534. X        }
  535. X        /*
  536. X         * Use a separate .newsrc file for every spooldir 
  537. X         */
  538. X        sprintf (newsrc, "%s/.newsrc", rcdir);
  539. X        sprintf (newnewsrc, "%s/.newnewsrc", rcdir);
  540. X
  541. X        spooldir_is_active = FALSE;
  542. X        reread_active_file = FALSE;
  543. X        alarm (0);
  544. X    } else {
  545. X        if (stat (rcdir, &sb) == -1) {
  546. X            mkdir (rcdir, 0755);
  547. X        }
  548. X        sprintf (rcdir,  "%s/%s", get_val ("TINDIR", homedir), RCDIR);
  549. X        sprintf (rcfile,   "%s/%s", rcdir, RCFILE);
  550. X        sprintf (killfile, "%s/%s", rcdir, KILLFILE);
  551. X        sprintf (postfile, "%s/%s", rcdir, POSTFILE);
  552. X        sprintf (unthreadfile, "%s/%s", rcdir, UNTHREADFILE);
  553. X        sprintf (newsrc, "%s/.newsrc", homedir);
  554. X        sprintf (newnewsrc, "%s/.newnewsrc", homedir);
  555. X
  556. X        spooldir_is_active = TRUE;
  557. X        reread_active_file = TRUE;
  558. X    }
  559. X    sprintf (indexdir, "%s/%s", rcdir, INDEXDIR);
  560. X    if (stat (indexdir, &sb) == -1) {
  561. X        mkdir (indexdir, 0755);
  562. X    }
  563. X}
  564. X
  565. X
  566. Xint create_mail_save_dirs ()
  567. X{
  568. X    int created = FALSE;
  569. X    struct stat sb;
  570. X    
  571. X    if (stat (default_maildir, &sb) == -1) {
  572. X        mkdir (default_maildir, 0755);
  573. X        created = TRUE;
  574. X    }
  575. X    if (stat (default_savedir, &sb) == -1) {
  576. X        mkdir (default_savedir, 0755);
  577. X        created = TRUE;
  578. X    }
  579. X    
  580. X    return (created);
  581. X}
  582. END_OF_FILE
  583.   if test 15082 -ne `wc -c <'init.c'`; then
  584.     echo shar: \"'init.c'\" unpacked with wrong size!
  585.   fi
  586.   # end of 'init.c'
  587. fi
  588. if test -f 'newsrc.c' -a "${1}" != "-c" ; then 
  589.   echo shar: Will not clobber existing file \"'newsrc.c'\"
  590. else
  591.   echo shar: Extracting \"'newsrc.c'\" \(20406 characters\)
  592.   sed "s/^X//" >'newsrc.c' <<'END_OF_FILE'
  593. X/*
  594. X *  Project   : tin - a threaded Netnews reader
  595. X *  Module    : newsrc.c
  596. X *  Author    : I.Lea & R.Skrenta
  597. X *  Created   : 01-04-91
  598. X *  Updated   : 19-04-92
  599. X *  Notes     :
  600. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  601. X *              You may  freely  copy or  redistribute  this software,
  602. X *              so  long as there is no profit made from its use, sale
  603. X *              trade or  reproduction.  You may not change this copy-
  604. X *              right notice, and it must be included in any copy made
  605. X */
  606. X
  607. X#include    "tin.h"
  608. X
  609. X
  610. X/*
  611. X * Automatically subscribe user to newsgroups specified in
  612. X * /usr/lib/news/subscribe (locally) or same file but from
  613. X * NNTP server (LIST AUTOSUBSCRIBE) and create .newsrc
  614. X */
  615. X
  616. Xint auto_subscribe_groups ()
  617. X{
  618. X    char buf[LEN];
  619. X    FILE *fp_newsrc;
  620. X    FILE *fp_subs;
  621. X    int len;
  622. X    int ret_code = FALSE;
  623. X    
  624. X    if ((fp_subs = open_subscription_fp ()) != NULL) {
  625. X        if ((fp_newsrc = fopen (newsrc, "w")) != NULL) {
  626. X            while (fgets (buf, sizeof (buf), fp_subs) != NULL) {
  627. X                len = strlen (buf);
  628. X                if (len > 1) {
  629. X                    buf[len-1] = '\0';
  630. X                    fprintf (fp_newsrc, "%s:\n", buf);
  631. X                }    
  632. X            }    
  633. X            fclose (fp_newsrc);
  634. X            ret_code = TRUE;
  635. X        }    
  636. X        fclose (fp_subs);
  637. X    }
  638. X
  639. X    return (ret_code);
  640. X}
  641. X
  642. X/*
  643. X * make a backup of users .newsrc in case of the bogie man
  644. X */
  645. X
  646. Xvoid backup_newsrc ()
  647. X{
  648. X    char buf[8192];
  649. X    FILE *fp_newsrc, *fp_backup;
  650. X    
  651. X    if ((fp_newsrc = fopen (newsrc, "r")) != NULL) {
  652. X        sprintf (buf, "%s/.oldnewsrc", homedir);
  653. X        unlink (buf);    /* because rn makes a link of .newsrc -> .oldnewsrc */
  654. X        if ((fp_backup = fopen (buf, "w")) != NULL) {
  655. X            while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) {
  656. X                fputs (buf, fp_backup);
  657. X            }
  658. X            fclose (fp_backup);
  659. X        }
  660. X        fclose (fp_newsrc);
  661. X    }
  662. X}
  663. X
  664. X/*
  665. X *  Read $HOME/.newsrc into my_group[]. my_group[] ints point to
  666. X *  active[] entries.  Sub_only determines  whether to just read
  667. X *  subscribed groups or all of them.
  668. X */
  669. X
  670. Xvoid read_newsrc (sub_only)
  671. X    int sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  672. X{
  673. X    char c, *p, buf[8192];
  674. X    char old_groups[LEN];
  675. X    FILE *fp = (FILE *) 0;
  676. X    FILE *fp_old = (FILE *) 0;
  677. X    int i;
  678. X    int remove_old_groups = FALSE;
  679. X
  680. X    group_top = 0;
  681. X
  682. Xreread_newsrc:
  683. X
  684. X    if ((fp = fopen (newsrc, "r")) == NULL) {    /* attempt to make a .newsrc */
  685. X        if (auto_subscribe_groups ()) {        /* attempt to auto create newsrc */
  686. X            goto reread_newsrc;
  687. X        }    
  688. X        for (i = 0; i < num_active; i++) {
  689. X            if (group_top >= max_active) {
  690. X                expand_active ();
  691. X            }
  692. X            my_group[group_top] = i;
  693. X            active[i].flag = 0;
  694. X            unread[group_top] = -1;
  695. X            group_top++;
  696. X        }
  697. X        write_newsrc ();
  698. X        return;
  699. X    }
  700. X
  701. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  702. X
  703. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  704. X        p = buf;
  705. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  706. X            p++;
  707. X        c = *p;
  708. X        *p++ = '\0';
  709. X
  710. X        if (c == '!' && sub_only)
  711. X            continue;        /* unsubscribed */
  712. X
  713. X        if ((i = add_group (buf, FALSE)) < 0) {
  714. X            if (! remove_old_groups) {
  715. X                if ((fp_old = fopen (old_groups, "w")) == NULL) {
  716. X                    perror_message (txt_cannot_open, old_groups);
  717. X                    continue;
  718. X                }
  719. X                remove_old_groups = TRUE;
  720. X            }
  721. X            fprintf (fp_old, "%s\n", buf);
  722. X            continue;
  723. X        }
  724. X
  725. X        if (c != '!')        /* if we're subscribed to it */
  726. X            active[my_group[i]].flag |= SUBSCRIBED;
  727. X
  728. X        unread[i] = parse_unread (p, my_group[i]);
  729. X    }
  730. X    fclose (fp);
  731. X
  732. X    /*
  733. X     *  rewrite newsrc to get rid of any non-existant groups 
  734. X     */
  735. X    if (remove_old_groups) {
  736. X        fclose (fp_old);
  737. X        rewrite_newsrc ();
  738. X    }
  739. X}
  740. X
  741. X/*
  742. X *  Write a new newsrc from my_group[] and active[] mygroup if
  743. X *  rewriting to get rid of groups that don't exist any longer. Used
  744. X *  to a create a new .newsrc if there isn't one already, or when
  745. X *  the newsrc is reset.
  746. X */
  747. X
  748. Xvoid write_newsrc ()
  749. X{
  750. X    FILE *fp;
  751. X    int i;
  752. X
  753. X    if ((fp = fopen (newsrc, "w")) == NULL) {
  754. X        return;
  755. X    }
  756. X
  757. X    wait_message (txt_creating_newsrc);
  758. X
  759. X    for (i=0 ; i < num_active ; i++) {
  760. X        fprintf (fp, "%s! \n", active[i].name);
  761. X    }
  762. X
  763. X    fclose (fp);
  764. X}
  765. X
  766. X/*
  767. X *  Rewrite newsrc to get rid of groups that don't exist any longer.
  768. X */
  769. X
  770. Xvoid rewrite_newsrc ()
  771. X{
  772. X    char buf[8192], old[LEN];
  773. X    char old_groups[LEN];
  774. X    FILE *fp, *fp_old, *fp_new;
  775. X    int found_old_group, len;    
  776. X
  777. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  778. X
  779. X    if ((fp = fopen (newsrc, "r")) == NULL)
  780. X        goto removed_old_groups_done;
  781. X
  782. X    if ((fp_old = fopen (old_groups, "r")) == NULL)
  783. X        goto removed_old_groups_done;
  784. X
  785. X    if ((fp_new = fopen (newnewsrc, "w")) == NULL)
  786. X        goto removed_old_groups_done;
  787. X
  788. X    while (fgets (buf, sizeof buf, fp) != NULL) {            /* read group from newsrc */
  789. X        rewind (fp_old);
  790. X        found_old_group = FALSE;    
  791. X        while (fgets (old, sizeof old, fp_old) != NULL) {    /* read group from oldgroups */
  792. X            len = strlen (old)-1;
  793. X            if ((buf[len] == ':' || buf[len] == '!') &&
  794. X                strncmp (buf, old, len) == 0) {
  795. X                old[len] = '\0';
  796. X                sprintf (msg, txt_deleting_from_newsrc, old);
  797. X                wait_message (msg);
  798. X                if (cmd_line) {
  799. X                    wait_message ("\n");
  800. X                }    
  801. X                found_old_group = TRUE;    
  802. X            }
  803. X        }
  804. X        if (! found_old_group) {
  805. X            fprintf (fp_new, "%s", buf);
  806. X        }
  807. X    }
  808. X    
  809. X    fclose (fp);
  810. X    fclose (fp_old);
  811. X    fclose (fp_new);
  812. X
  813. X    rename_file (newnewsrc, newsrc);
  814. X
  815. Xremoved_old_groups_done:
  816. X    unlink (old_groups);
  817. X}
  818. X
  819. X/*
  820. X *  Load the sequencer rang lists and mark arts[] according to the
  821. X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  822. X */
  823. X
  824. Xvoid read_newsrc_line (group)
  825. X    char *group;
  826. X{
  827. X    FILE *fp;
  828. X    char buf[8192];
  829. X    char *p;
  830. X
  831. X    if ((fp = fopen (newsrc, "r")) == NULL)
  832. X        return;
  833. X
  834. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  835. X        p = buf;
  836. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  837. X            p++;
  838. X        *p++ = '\0';
  839. X        if (strcmp (buf, group) != 0)
  840. X            continue;
  841. X        parse_seq (p);
  842. X        break;
  843. X    }
  844. X
  845. X    fclose (fp);
  846. X}
  847. X
  848. X/*
  849. X *  For our current group, update the sequencer information in .newsrc
  850. X */
  851. X
  852. Xvoid update_newsrc (group, groupnum, mark_unread)
  853. X    char *group;
  854. X    int groupnum;            /* index into active[] for this group */
  855. X    int mark_unread;
  856. X{
  857. X    FILE *fp;
  858. X    FILE *newfp;
  859. X    char buf[8192];
  860. X    char *p;
  861. X    char c;
  862. X
  863. X    if ((newfp = fopen (newnewsrc, "w")) == NULL) {
  864. X        goto update_done;
  865. X    }
  866. X
  867. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  868. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  869. X            for (p = buf; *p; p++)
  870. X                if (*p == '\n') {
  871. X                    *p = '\0';
  872. X                    break;
  873. X                }
  874. X
  875. X            p = buf;
  876. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  877. X                    p++;
  878. X            c = *p;
  879. X            if (c != '\0')
  880. X                *p++ = '\0';
  881. X
  882. X            if (c != '!' && c != ' ')
  883. X                c = ':';
  884. X
  885. X            if (strcmp (buf, group) == 0) {
  886. X                if (mark_unread) {
  887. X                    fprintf (newfp, "%s%c\n", buf, c);
  888. X                } else {
  889. X                    fprintf (newfp, "%s%c ", buf, c);
  890. X                    print_seq (newfp, groupnum);
  891. X                    fprintf (newfp, "\n");
  892. X                }
  893. X            } else
  894. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  895. X        }
  896. X        fclose (fp);
  897. X    }
  898. X
  899. X    fclose (newfp);
  900. X    rename_file (newnewsrc, newsrc);
  901. X
  902. Xupdate_done:
  903. X    ;
  904. X}
  905. X
  906. X/*
  907. X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  908. X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  909. X *  in active[].
  910. X */
  911. X
  912. Xvoid subscribe (group, ch, num, out_seq)
  913. X    char *group;
  914. X    char ch;
  915. X    int num;
  916. X    int out_seq;                /* output sequencer info? */
  917. X{
  918. X    FILE *fp;
  919. X    FILE *newfp;
  920. X    char buf[8192];
  921. X    char *p;
  922. X    char c;
  923. X    int gotit = FALSE;
  924. X
  925. X    if (ch == '!')
  926. X        active[num].flag &= ~SUBSCRIBED;
  927. X    else
  928. X        active[num].flag |= SUBSCRIBED;
  929. X
  930. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  931. X        goto subscribe_done;
  932. X
  933. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  934. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  935. X            if (strncmp ("options ", buf, 8) == 0) {
  936. X                fprintf (newfp, buf);
  937. X            } else {
  938. X                for (p = buf; *p; p++) {
  939. X                    if (*p == '\n') {
  940. X                        *p = '\0';
  941. X                        break;
  942. X                    }
  943. X                }    
  944. X
  945. X                p = buf;
  946. X                while (*p && *p != ' ' && *p != ':' && *p != '!')
  947. X                        p++;
  948. X                c = *p;
  949. X                if (c != '\0')
  950. X                    *p++ = '\0';
  951. X
  952. X                if (c != '!')
  953. X                    c = ':';
  954. X
  955. X                if (strcmp (buf, group) == 0) {
  956. X                    fprintf (newfp, "%s%c%s\n", buf, ch, p);
  957. X                    gotit = TRUE;
  958. X                } else {
  959. X                    fprintf (newfp, "%s%c%s\n", buf, c, p);
  960. X                }
  961. X            }
  962. X        }
  963. X        fclose (fp);
  964. X    }
  965. X
  966. X    if (! gotit) {
  967. X        if (out_seq) {
  968. X            fprintf (newfp, "%s%c ", group, ch);
  969. X            print_seq (newfp, num);
  970. X            fprintf (newfp, "\n");
  971. X        } else
  972. X            fprintf (newfp, "%s%c\n", group, ch);
  973. X    }
  974. X
  975. X    fclose (newfp);
  976. X    rename_file (newnewsrc, newsrc);
  977. X
  978. Xsubscribe_done:
  979. X    ;
  980. X}
  981. X
  982. X
  983. Xvoid reset_newsrc ()
  984. X{
  985. X    FILE *fp;
  986. X    FILE *newfp;
  987. X    char buf[8192];
  988. X    char *p;
  989. X    char c;
  990. X    int i;
  991. X
  992. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  993. X        goto update_done;
  994. X
  995. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  996. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  997. X            for (p = buf; *p && *p != '\n'; p++)
  998. X                continue;
  999. X            *p = '\0';
  1000. X
  1001. X            p = buf;
  1002. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1003. X                    p++;
  1004. X            c = *p;
  1005. X            if (c != '\0')
  1006. X                *p++ = '\0';
  1007. X
  1008. X            if (c != '!')
  1009. X                c = ':';
  1010. X
  1011. X            fprintf (newfp, "%s%c\n", buf, c);
  1012. X        }
  1013. X        fclose (fp);
  1014. X    }
  1015. X
  1016. X    fclose (newfp);
  1017. X    rename_file (newnewsrc, newsrc);
  1018. X
  1019. Xupdate_done:
  1020. X    for (i = 0; i < group_top; i++)
  1021. X        unread[i] = -1;
  1022. X}
  1023. X
  1024. X
  1025. Xvoid delete_group (group)
  1026. X    char *group;
  1027. X{
  1028. X    FILE *fp;
  1029. X    FILE *newfp;
  1030. X    char buf[8192];
  1031. X    char *p;
  1032. X    char c;
  1033. X    int gotit = FALSE;
  1034. X    FILE *del;
  1035. X
  1036. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1037. X        goto del_done;
  1038. X
  1039. X    if ((del = fopen (delgroups, "a+")) == NULL)
  1040. X        goto del_done;
  1041. X
  1042. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1043. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1044. X            for (p = buf; *p && *p != '\n'; p++)
  1045. X                continue;
  1046. X            *p = '\0';
  1047. X
  1048. X            p = buf;
  1049. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1050. X                    p++;
  1051. X            c = *p;
  1052. X            if (c != '\0')
  1053. X                *p++ = '\0';
  1054. X
  1055. X            if (c != '!')
  1056. X                c = ':';
  1057. X
  1058. X            if (strcmp (buf, group) == 0) {
  1059. X                fprintf (del, "%s%c%s\n", buf, c, p);
  1060. X                gotit = TRUE;
  1061. X            } else
  1062. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  1063. X        }
  1064. X        fclose (fp);
  1065. X    }
  1066. X
  1067. X    fclose (newfp);
  1068. X
  1069. X    if (! gotit)
  1070. X        fprintf (del, "%s! \n", group);
  1071. X
  1072. X    fclose (del);
  1073. X    rename_file (newnewsrc, newsrc);
  1074. X
  1075. Xdel_done:
  1076. X    ;
  1077. X}
  1078. X
  1079. X
  1080. Xint undel_group ()
  1081. X{
  1082. X    FILE *del;
  1083. X    FILE *newfp;
  1084. X    FILE *fp;
  1085. X    char buf[2][8192];
  1086. X    char *p;
  1087. X    int which = 0;
  1088. X    long h;
  1089. X    extern int cur_groupnum;
  1090. X    int i, j;
  1091. X    char c;
  1092. X
  1093. X    if ((del = fopen(delgroups, "r")) == NULL) {
  1094. X        return FALSE;
  1095. X    }
  1096. X
  1097. X    unlink(delgroups);
  1098. X    
  1099. X    if ((newfp = fopen(delgroups, "w")) == NULL) {
  1100. X        return FALSE;
  1101. X    }
  1102. X
  1103. X    buf[0][0] = '\0';
  1104. X    buf[1][0] = '\0';
  1105. X
  1106. X    while (fgets(buf[which], sizeof (buf[which]), del) != NULL) {
  1107. X        which = !which;
  1108. X        if (*buf[which])
  1109. X            fputs(buf[which], newfp);
  1110. X    }
  1111. X
  1112. X    fclose(del);
  1113. X    fclose(newfp);
  1114. X    which = !which;
  1115. X
  1116. X    if (!*buf[which]) {
  1117. X        return FALSE;
  1118. X    }
  1119. X
  1120. X    for (p = buf[which]; *p && *p != '\n'; p++)
  1121. X        continue;
  1122. X    *p = '\0';
  1123. X
  1124. X    p = buf[which];
  1125. X    while (*p && *p != ' ' && *p != ':' && *p != '!')
  1126. X        p++;
  1127. X    c = *p;
  1128. X    if (c != '\0')
  1129. X        *p++ = '\0';
  1130. X
  1131. X    if (c != '!')
  1132. X        c = ':';
  1133. X
  1134. X    h = hash_groupname (buf[which]);
  1135. X
  1136. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  1137. X        if (strcmp(buf[which], active[i].name) == 0) {
  1138. X            for (j = 0; j < group_top; j++)
  1139. X                if (my_group[j] == i) {
  1140. X                    return j;
  1141. X                }
  1142. X
  1143. X            active[i].flag &= ~UNSUBSCRIBED;   /* mark that we got it */
  1144. X            if (c != '!')
  1145. X                active[i].flag |= SUBSCRIBED;
  1146. X
  1147. X            if (group_top >= max_active)
  1148. X                expand_active ();
  1149. X            group_top++;
  1150. X            for (j = group_top; j > cur_groupnum; j--) {
  1151. X                my_group[j] = my_group[j-1];
  1152. X                unread[j] = unread[j-1];
  1153. X            }
  1154. X            my_group[cur_groupnum] = i;
  1155. X            unread[cur_groupnum] = parse_unread(p, i);
  1156. X
  1157. X            if ((fp = fopen(newsrc, "r")) == NULL) {
  1158. X                return FALSE;
  1159. X            }
  1160. X            if ((newfp = fopen(newnewsrc, "w")) == NULL) {
  1161. X                fclose(fp);
  1162. X                return FALSE;
  1163. X            }
  1164. X            i = 0;
  1165. X            while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) {
  1166. X                for (p = buf[!which]; *p && *p != '\n'; p++)
  1167. X                    continue;
  1168. X                *p = '\0';
  1169. X
  1170. X                p = buf[!which];
  1171. X                while (*p && *p!=' ' && *p != ':' && *p != '!')
  1172. X                    p++;
  1173. X                c = *p;
  1174. X                if (c != '\0')
  1175. X                    *p++ = '\0';
  1176. X
  1177. X                if (c != '!')
  1178. X                    c = ':';
  1179. X
  1180. X                while (i < cur_groupnum) {
  1181. X                    if (strcmp(buf[!which],
  1182. X                      active[my_group[i]].name) == 0) {
  1183. X                        fprintf(newfp, "%s%c%s\n",
  1184. X                            buf[!which], c, p);
  1185. X                        goto foo_cont;
  1186. X                    }
  1187. X                    i++;
  1188. X                }
  1189. X                fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  1190. X                fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  1191. X                break;
  1192. Xfoo_cont:;
  1193. X            }
  1194. X
  1195. X            while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL)
  1196. X                fputs (buf[!which], newfp);
  1197. X
  1198. X            fclose (newfp);
  1199. X            fclose (fp);
  1200. X            rename_file (newnewsrc, newsrc);
  1201. X            return TRUE;
  1202. X        }
  1203. X    }
  1204. X    return FALSE;
  1205. X}
  1206. X
  1207. X
  1208. Xvoid mark_group_read (group, groupnum)
  1209. X    char *group;
  1210. X    int groupnum;            /* index into active[] for this group */
  1211. X{
  1212. X    FILE *fp;
  1213. X    FILE *newfp;
  1214. X    char buf[8192];
  1215. X    char *p;
  1216. X    char c;
  1217. X
  1218. X    if (active[groupnum].max < 2)
  1219. X        return;
  1220. X
  1221. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1222. X        goto mark_group_read_done;
  1223. X
  1224. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1225. X        while (fgets(buf, sizeof (buf), fp) != NULL) {
  1226. X            for (p = buf; *p; p++)
  1227. X                if (*p == '\n') {
  1228. X                    *p = '\0';
  1229. X                    break;
  1230. X                }
  1231. X
  1232. X            p = buf;
  1233. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1234. X                    p++;
  1235. X            c = *p;
  1236. X            if (c != '\0')
  1237. X                *p++ = '\0';
  1238. X
  1239. X            if (c != '!')
  1240. X                c = ':';
  1241. X
  1242. X            if (strcmp (buf, group) == 0) {
  1243. X                fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max);
  1244. X            } else
  1245. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  1246. X        }
  1247. X        fclose (fp);
  1248. X    }
  1249. X
  1250. X    fclose (newfp);
  1251. X    rename_file (newnewsrc, newsrc);
  1252. X
  1253. Xmark_group_read_done:
  1254. X    ;
  1255. X}
  1256. X
  1257. X
  1258. Xvoid parse_seq(s)
  1259. X    char *s;
  1260. X{
  1261. X    long low, high;
  1262. X    int i;
  1263. X
  1264. X    while (*s) {
  1265. X        while (*s && (*s < '0' || *s > '9'))
  1266. X            s++;
  1267. X
  1268. X        if (*s && *s >= '0' && *s <= '9') {
  1269. X            low = (long) atol (s);
  1270. X            while (*s && *s >= '0' && *s <= '9')
  1271. X                s++;
  1272. X            if (*s == '-') {
  1273. X                s++;
  1274. X                high = (long) atol (s);
  1275. X                while (*s && *s >= '0' && *s <= '9')
  1276. X                    s++;
  1277. X            }  else
  1278. X                high = low;
  1279. X
  1280. X            for (i = 0; i < top; i++)
  1281. X                if (arts[i].artnum >= low && arts[i].artnum <= high)
  1282. X                    arts[i].unread = ART_READ;
  1283. X        }
  1284. X    }
  1285. X}
  1286. X
  1287. X/*
  1288. X *  Read the first range from the .newsrc sequencer information.
  1289. X *  If the top of the first range is higher than what the active
  1290. X *  file claims is the bottom, use it as the new bottom instead.
  1291. X */
  1292. X
  1293. Xint parse_unread (s, groupnum)
  1294. X    char *s;
  1295. X    int groupnum;            /* index for group in active[] */
  1296. X{
  1297. X    long low, high;
  1298. X    long last_high;
  1299. X    int sum = 0;
  1300. X    int gotone = FALSE;
  1301. X    int n;
  1302. X
  1303. X    high = 0;
  1304. X
  1305. X    if (*s) {
  1306. X        while (*s && (*s < '0' || *s > '9')) {
  1307. X            s++;
  1308. X        }    
  1309. X
  1310. X        if (*s && *s >= '0' && *s <= '9') {
  1311. X            low = (long) atol (s);
  1312. X            while (*s && *s >= '0' && *s <= '9')
  1313. X                s++;
  1314. X            if (*s == '-') {
  1315. X                s++;
  1316. X                high = (long) atol (s);
  1317. X                while (*s && *s >= '0' && *s <= '9')
  1318. X                    s++;
  1319. X            }  else
  1320. X                high = low;
  1321. X            gotone = TRUE;
  1322. X        }
  1323. X    }
  1324. X
  1325. X    /* Note that in the active file min will be one greater than max
  1326. X     * when there are no articles in the spool directory. ie., it is
  1327. X      * always true that "max - min + 1 = article count (including
  1328. X      * expired articles)"
  1329. X      */
  1330. X
  1331. X    if (high < active[groupnum].min - 1)
  1332. X        high = active[groupnum].min - 1;
  1333. X
  1334. X    while (*s) {
  1335. X        last_high = high;
  1336. X
  1337. X        while (*s && (*s < '0' || *s > '9'))
  1338. X            s++;
  1339. X
  1340. X        if (*s && *s >= '0' && *s <= '9') {
  1341. X            low = (long) atol (s);
  1342. X            while (*s && *s >= '0' && *s <= '9')
  1343. X                s++;
  1344. X            if (*s == '-') {
  1345. X                s++;
  1346. X                high = (long) atol (s);
  1347. X                while (*s && *s >= '0' && *s <= '9')
  1348. X                    s++;
  1349. X            }  else
  1350. X                high = low;
  1351. X
  1352. X            if (low > last_high)    /* otherwise seq out of order */
  1353. X                sum += (low - last_high) - 1;
  1354. X        }
  1355. X    }
  1356. X
  1357. X    if (gotone) {
  1358. X        if (active[groupnum].max > high)
  1359. X            sum += active[groupnum].max - high;
  1360. X        return sum;
  1361. X    }
  1362. X
  1363. X    n = (int) (active[groupnum].max - active[groupnum].min) + 1;
  1364. X    
  1365. X    if (n < 0)
  1366. X        return -1;
  1367. X    else
  1368. X        return (n);
  1369. X}
  1370. X
  1371. X
  1372. Xint get_line_unread(group, groupnum)
  1373. X    char *group;
  1374. X    int groupnum;                /* index for group in active[] */
  1375. X{
  1376. X    FILE *fp;
  1377. X    char buf[8192];
  1378. X    char *p;
  1379. X    int ret = -1;
  1380. X
  1381. X    if ((fp = fopen(newsrc, "r")) == NULL)
  1382. X        return -1;
  1383. X
  1384. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1385. X        p = buf;
  1386. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1387. X            p++;
  1388. X        *p++ = '\0';
  1389. X        
  1390. X        if (strcmp (buf, group) != 0)
  1391. X            continue;
  1392. X            
  1393. X        ret = parse_unread (p, groupnum);
  1394. X        break;
  1395. X    }
  1396. X
  1397. X    fclose (fp);
  1398. X    return ret;
  1399. X}
  1400. X
  1401. X
  1402. Xvoid print_seq (fp, groupnum)
  1403. X    FILE *fp;
  1404. X    int groupnum;            /* index into active[] for this group */
  1405. X{
  1406. X    long int artnum, last_read, artmax;
  1407. X    int i;
  1408. X    int flag = FALSE;
  1409. X    
  1410. X    assert(top >= 0);
  1411. X
  1412. X      /*
  1413. X       *  sort into the same order as in the spool area for writing
  1414. X       *  read article numbers to ~/.newsrc
  1415. X       */
  1416. X     if (top > 0)
  1417. X         qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  1418. X  
  1419. X     /*
  1420. X      * Note that killed and expired articles do not appear in arts[].
  1421. X      * So, even if top is 0 there may be sequencer info to output.
  1422. X     */
  1423. X     if (top > 0 && arts[top-1].artnum > active[groupnum].max)
  1424. X         artmax = arts[top-1].artnum;
  1425. X     else
  1426. X         artmax = active[groupnum].max;
  1427. X     for (artnum=1, i=0; artnum <= artmax; ++artnum, ++i) {
  1428. X         assert(i<=top);
  1429. X         if (i==top || arts[i].unread == ART_READ || artnum != arts[i].artnum) {
  1430. X              if (flag)
  1431. X                  fprintf(fp, ",");
  1432. X              else
  1433. X                  flag = TRUE;
  1434. X             fprintf (fp, "%ld", artnum);
  1435. X             while (i < top && arts[i].unread == ART_READ)
  1436. X                 ++i;
  1437. X             last_read = (i<top ? arts[i].artnum - 1 : artmax);
  1438. X             if (last_read != artnum) {
  1439. X                 fprintf(fp, "-%ld", last_read);
  1440. X              }
  1441. X
  1442. X             assert(i <= top);
  1443. X             if (i == top)
  1444. X                 break;
  1445. X             artnum = arts[i].artnum;
  1446. X          }
  1447. X      }
  1448. X  
  1449. X      fflush (fp);
  1450. X     if (top == 0)
  1451. X         return;
  1452. X
  1453. X    /*
  1454. X     *  resort into required sort order
  1455. X     */
  1456. X    switch (sort_art_type) {
  1457. X        case SORT_BY_NOTHING:        /* already sorted above */
  1458. X            break;
  1459. X        case SORT_BY_SUBJ_DESCEND:
  1460. X        case SORT_BY_SUBJ_ASCEND:
  1461. X            qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
  1462. X            break;
  1463. X        case SORT_BY_FROM_DESCEND:
  1464. X        case SORT_BY_FROM_ASCEND:
  1465. X            qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
  1466. X            break;
  1467. X        case SORT_BY_DATE_DESCEND:
  1468. X        case SORT_BY_DATE_ASCEND:
  1469. X            qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
  1470. X            break;
  1471. X    }
  1472. X}
  1473. X
  1474. X/*
  1475. X *  rewrite .newsrc and position group at specifed position
  1476. X */
  1477. X
  1478. Xint pos_group_in_newsrc (group, pos)
  1479. X    char *group;
  1480. X    int pos;
  1481. X{
  1482. X    char sub[1024];
  1483. X    char unsub[1024];
  1484. X    char buf[1024];
  1485. X    char newsgroup[1024];
  1486. X    extern int cur_groupnum;
  1487. X    FILE *fp_in, *fp_out;
  1488. X    FILE *fp_sub, *fp_unsub;
  1489. X    int repositioned = FALSE;
  1490. X    int subscribed_pos = 1;
  1491. X    int group_len;
  1492. X    int option_line = FALSE;
  1493. X    int ret_code = FALSE;
  1494. X
  1495. X    if ((fp_in = fopen (newsrc, "r")) == NULL) {
  1496. X        goto rewrite_group_done;
  1497. X    }
  1498. X    if ((fp_out = fopen (newnewsrc, "w")) == NULL) {
  1499. X        goto rewrite_group_done;
  1500. X    }
  1501. X
  1502. X    sprintf (sub, "/tmp/.subrc.%d", process_id);
  1503. X    sprintf (unsub, "/tmp/.unsubrc.%d", process_id);
  1504. X
  1505. X    if ((fp_sub = fopen (sub, "w")) == NULL) {
  1506. X        goto rewrite_group_done;
  1507. X    }
  1508. X    if ((fp_unsub = fopen (unsub, "w")) == NULL) {
  1509. X        goto rewrite_group_done;
  1510. X    }
  1511. X
  1512. X    /*
  1513. X     *  split newsrc into subscribed and unsubscribed to files
  1514. X     */
  1515. X    group_len = strlen (group);
  1516. X
  1517. X    while (fgets (buf, sizeof (buf), fp_in) != NULL) {
  1518. X        if (strncmp (group, buf, group_len) == 0 && buf[group_len] == ':') {
  1519. X            my_strncpy (newsgroup, buf, sizeof (newsgroup));
  1520. X        } else if (strchr (buf, ':') != NULL) {
  1521. X            fprintf (fp_sub, "%s", buf);
  1522. X        } else if (strchr (buf, '!') != NULL) {
  1523. X            fprintf (fp_unsub, "%s", buf);
  1524. X        } else {    /* options line at beginning of .newsrc */
  1525. X            fprintf (fp_sub, "%s", buf);
  1526. X            option_line = TRUE;
  1527. X        }
  1528. X    }
  1529. X
  1530. X    fclose (fp_in);
  1531. X    fclose (fp_sub);
  1532. X    fclose (fp_unsub);
  1533. X
  1534. X    /*
  1535. X     *  write subscribed groups & position group to newnewsrc
  1536. X     */
  1537. X    if ((fp_sub = fopen (sub, "r")) == NULL) {
  1538. X        unlink (sub);
  1539. X        goto rewrite_group_done;
  1540. X    }
  1541. X    while (fgets (buf, sizeof (buf), fp_sub) != NULL) {
  1542. X        if (option_line) {
  1543. X            if (strchr (buf, ':') == NULL && strchr (buf, '!') == NULL) {
  1544. X                fprintf (fp_out, "%s", buf);
  1545. X                continue;
  1546. X            } else {
  1547. X                option_line = FALSE;
  1548. X            }
  1549. X        }
  1550. X
  1551. X        if (pos == subscribed_pos) {
  1552. X            fprintf (fp_out, "%s\n", newsgroup);
  1553. X            repositioned = TRUE;
  1554. X        }
  1555. X        
  1556. X        fprintf (fp_out, "%s", buf);
  1557. X
  1558. X        subscribed_pos++;
  1559. X    }
  1560. X    if (! repositioned) {
  1561. X        fprintf (fp_out, "%s\n", newsgroup);
  1562. X        repositioned = TRUE;
  1563. X    }
  1564. X    
  1565. X    fclose (fp_sub);
  1566. X     unlink (sub);
  1567. X
  1568. X    /*
  1569. X     *  write unsubscribed groups to newnewsrc
  1570. X     */
  1571. X    if ((fp_unsub = fopen (unsub, "r")) == NULL) {
  1572. X        unlink (unsub);
  1573. X        goto rewrite_group_done;
  1574. X    }
  1575. X    while (fgets (buf, sizeof (buf), fp_unsub) != NULL) {
  1576. X        fprintf (fp_out, "%s", buf);
  1577. X    }
  1578. X
  1579. X    fclose (fp_unsub);
  1580. X    unlink (unsub);
  1581. X    fclose (fp_out);
  1582. X
  1583. X    if (repositioned) {
  1584. X        cur_groupnum = pos;
  1585. X        rename_file (newnewsrc, newsrc);
  1586. X        ret_code = TRUE;
  1587. X    }
  1588. X
  1589. Xrewrite_group_done:
  1590. X    return ret_code;
  1591. X}
  1592. X
  1593. X/*
  1594. X *  mark all orther Xref: articles as read when one article read
  1595. X *  Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
  1596. X */
  1597. Xvoid mark_all_xref_read (xref_line)
  1598. X    char *xref_line; 
  1599. X{
  1600. X/*
  1601. X    char group[LEN];
  1602. X    long artnum;
  1603. X*/    
  1604. X    if (xref_line == (char *) 0) {
  1605. X        return;
  1606. X    }
  1607. X
  1608. X    /*
  1609. X     *  check sitename macthes nodename of current machine
  1610. X     */
  1611. X
  1612. X    /*
  1613. X     *  tokenize each pair and update that newsgroup if it
  1614. X     *  is in users my_group[].
  1615. X     */
  1616. X     
  1617. X}
  1618. END_OF_FILE
  1619.   if test 20406 -ne `wc -c <'newsrc.c'`; then
  1620.     echo shar: \"'newsrc.c'\" unpacked with wrong size!
  1621.   fi
  1622.   # end of 'newsrc.c'
  1623. fi
  1624. if test -f 'nntplib.c' -a "${1}" != "-c" ; then 
  1625.   echo shar: Will not clobber existing file \"'nntplib.c'\"
  1626. else
  1627.   echo shar: Extracting \"'nntplib.c'\" \(14736 characters\)
  1628.   sed "s/^X//" >'nntplib.c' <<'END_OF_FILE'
  1629. X/*
  1630. X *  Project   : tin - a threaded Netnews reader
  1631. X *  Module    : nntplib.c
  1632. X *  Author    : S.Barber & I.Lea
  1633. X *  Created   : 12-01-91
  1634. X *  Updated   : 06-05-92
  1635. X *  Notes     : NNTP client routines taken from clientlib.c v1.6
  1636. X *              1.5.11 (10 February 1991)
  1637. X *  Copyright : (c) Copyright 1991-92 by Stan Barber & Iain Lea
  1638. X *              Permission is hereby granted to copy, reproduce, redistribute
  1639. X *              or otherwise use this software  as long as: there is no
  1640. X *              monetary  profit  gained  specifically  from the use or
  1641. X *              reproduction or this software, it is not  sold, rented,
  1642. X *              traded or otherwise marketed, and this copyright notice
  1643. X *              is included prominently in any copy made. 
  1644. X */
  1645. X
  1646. X#include "tin.h"
  1647. X
  1648. X#ifdef NNTP_ONLY
  1649. X#    define    NNTP_ABLE
  1650. X#endif
  1651. X
  1652. X#ifndef CDROM_ABLE
  1653. X
  1654. XFILE    *ser_rd_fp = NULL;
  1655. XFILE    *ser_wr_fp = NULL;
  1656. X
  1657. X#ifdef NNTP_ABLE
  1658. X#    ifdef TLI
  1659. X#        include    <fcntl.h>
  1660. X#        include    <tiuser.h>
  1661. X#        include    <stropts.h>
  1662. X#        include    <sys/socket.h>
  1663. X#        ifdef WIN_TCP
  1664. X#            include    <sys/in.h>
  1665. X#        else
  1666. X#            include    <netinet/in.h>
  1667. X#        endif
  1668. X#        define    IPPORT_NNTP    ((unsigned short) 119)
  1669. X#        include     <netdb.h>    /* All TLI implementations may not have this */
  1670. X#    else
  1671. X#        ifdef apollo
  1672. X#            include </bsd4.3/usr/include/sys/socket.h>
  1673. X#            include </bsd4.3/usr/include/netinet/in.h>
  1674. X#            include </bsd4.3/usr/include/netdb.h>
  1675. X#        else
  1676. X#            include <sys/socket.h>
  1677. X#            include <netinet/in.h>
  1678. X#            ifndef EXCELAN
  1679. X#                include <netdb.h>
  1680. X#            endif
  1681. X#        endif
  1682. X#    endif /* !TLI */
  1683. X
  1684. X#    ifndef BSD
  1685. X#        define    index(a,b)    strchr(a,b)
  1686. X#        define    bcopy(a,b,c)    memcpy(b,a,c)
  1687. X#        define    bzero(a,b)    memset(a,'\0',b)
  1688. X#    endif
  1689. X
  1690. X#    ifdef EXCELAN
  1691. X#        define    IPPORT_NNTP    ((unsigned short) 119)
  1692. X#        if __STDC__
  1693. X            int connect (int, struct sockaddr *);
  1694. X            unsigned short htons (unsigned short);
  1695. X            unsigned long rhost (char **);
  1696. X            int rresvport (int);
  1697. X            int socket (int, struct sockproto *, struct sockaddr_in *, int);
  1698. X#        endif
  1699. X#    endif
  1700. X
  1701. X#    ifdef DECNET
  1702. X#        include <netdnet/dn.h>
  1703. X#        include <netdnet/dnetdb.h>
  1704. X#    endif
  1705. X
  1706. X#endif /* NNTP_ABLE */
  1707. X
  1708. X/*
  1709. X * getserverbyfile    Get the name of a server from a named file.
  1710. X *            Handle white space and comments.
  1711. X *            Use NNTPSERVER environment variable if set.
  1712. X *
  1713. X *    Parameters:    "file" is the name of the file to read.
  1714. X *
  1715. X *    Returns:    Pointer to static data area containing the
  1716. X *            first non-ws/comment line in the file.
  1717. X *            NULL on error (or lack of entry in file).
  1718. X *
  1719. X *    Side effects:    None.
  1720. X */
  1721. X
  1722. Xchar *getserverbyfile (file)
  1723. X    char    *file;
  1724. X{
  1725. X#ifdef NNTP_ABLE
  1726. X    extern int debug;
  1727. X    register FILE    *fp;
  1728. X    register char    *cp;
  1729. X    static char    buf[256];
  1730. X
  1731. X    if (debug == 1) {
  1732. X        wait_message ("USING BUILTIN NNTP");
  1733. X    }
  1734. X    
  1735. X    if (cp = (char *) getenv ("NNTPSERVER")) {
  1736. X        (void) strcpy (buf, cp);
  1737. X        return (buf);
  1738. X    }
  1739. X
  1740. X    if (file == NULL)
  1741. X        return (NULL);
  1742. X
  1743. X    if ((fp = fopen (file, "r")) == NULL)
  1744. X        return (NULL);
  1745. X
  1746. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  1747. X        if (*buf == '\n' || *buf == '#') {
  1748. X            continue;
  1749. X        }
  1750. X        cp = (char *) index(buf, '\n');
  1751. X        if (cp) {
  1752. X            *cp = '\0';
  1753. X        }
  1754. X        (void) fclose (fp);
  1755. X        return (buf);
  1756. X    }
  1757. X
  1758. X    (void) fclose (fp);
  1759. X#endif /* NNTP_ABLE */
  1760. X    return (NULL);             /* No entry */
  1761. X}
  1762. X
  1763. X/*
  1764. X * server_init  Get a connection to the remote news server.
  1765. X *
  1766. X *    Parameters:    "machine" is the machine to connect to.
  1767. X *
  1768. X *    Returns:    -1 on error
  1769. X *            server's initial response code on success.
  1770. X *
  1771. X *    Side effects:    Connects to server.
  1772. X *            "ser_rd_fp" and "ser_wr_fp" are fp's
  1773. X *            for reading and writing to server.
  1774. X */
  1775. X
  1776. Xint server_init (machine)
  1777. X    char    *machine;
  1778. X{
  1779. X#ifdef NNTP_ABLE
  1780. X    int    sockt_rd, sockt_wr;
  1781. X    char    line[256];
  1782. X#ifdef DECNET
  1783. X    char    *cp;
  1784. X
  1785. X    cp = (char *) index(machine, ':');
  1786. X
  1787. X    if (cp && cp[1] == ':') {
  1788. X        *cp = '\0';
  1789. X        sockt_rd = get_dnet_socket (machine);
  1790. X    } else {
  1791. X        sockt_rd = get_tcp_socket (machine);
  1792. X    }
  1793. X#else
  1794. X    sockt_rd = get_tcp_socket (machine);
  1795. X#endif
  1796. X
  1797. X    if (sockt_rd < 0)
  1798. X        return (-1);
  1799. X
  1800. X    /*
  1801. X     * Now we'll make file pointers (i.e., buffered I/O) out of
  1802. X     * the socket file descriptor.  Note that we can't just
  1803. X     * open a fp for reading and writing -- we have to open
  1804. X     * up two separate fp's, one for reading, one for writing.
  1805. X     */
  1806. X
  1807. X    if ((ser_rd_fp = (FILE *) fdopen (sockt_rd, "r")) == NULL) {
  1808. X        perror ("server_init: fdopen #1");
  1809. X        return (-1);
  1810. X    }
  1811. X
  1812. X    sockt_wr = dup (sockt_rd);
  1813. X#ifdef TLI
  1814. X    if (t_sync (sockt_rd) < 0) {    /* Sync up new fd with TLI */
  1815. X            t_error ("server_init: t_sync");
  1816. X        ser_rd_fp = NULL;        /* from above */
  1817. X        return (-1);
  1818. X    }
  1819. X#endif
  1820. X    if ((ser_wr_fp = (FILE *) fdopen (sockt_wr, "w")) == NULL) {
  1821. X        perror ("server_init: fdopen #2");
  1822. X        ser_rd_fp = NULL;        /* from above */
  1823. X        return (-1);
  1824. X    }
  1825. X
  1826. X    /*
  1827. X     * Now get the server's signon message
  1828. X     */
  1829. X
  1830. X    (void) get_server (line, sizeof (line));
  1831. X    return (atoi (line));
  1832. X#else
  1833. X    return (-1);
  1834. X#endif /* NNTP_ABLE */
  1835. X}
  1836. X
  1837. X/*
  1838. X * get_tcp_socket -- get us a socket connected to the news server.
  1839. X *
  1840. X *    Parameters:    "machine" is the machine the server is running on.
  1841. X *
  1842. X *    Returns:    Socket connected to the news server if
  1843. X *            all is ok, else -1 on error.
  1844. X *
  1845. X *    Side effects:    Connects to server.
  1846. X *
  1847. X *    Errors:        Printed via perror.
  1848. X */
  1849. X
  1850. Xint get_tcp_socket (machine)
  1851. X    char    *machine;    /* remote host */
  1852. X{
  1853. X#ifdef NNTP_ABLE
  1854. X    int    s = -1;
  1855. X    struct    sockaddr_in sin;
  1856. X#ifdef TLI 
  1857. X    struct    hostent *gethostbyname (), *hp;
  1858. X    struct    t_call    *callptr;
  1859. X
  1860. X    /*
  1861. X     * Create a TCP transport endpoint.
  1862. X     */
  1863. X    if ((s = t_open ("/dev/tcp", O_RDWR, (struct t_info*) 0)) < 0){
  1864. X        t_error ("t_open: can't t_open /dev/tcp");
  1865. X        return (-1);
  1866. X    }
  1867. X    if (t_bind (s, (struct t_bind *) 0, (struct t_bind *) 0) < 0) {
  1868. X           t_error ("t_bind");
  1869. X        t_close (s);
  1870. X        return (-1);
  1871. X    }
  1872. X    bzero((char *) &sin, sizeof (sin));    
  1873. X    sin.sin_family = AF_INET;
  1874. X    sin.sin_port = htons (IPPORT_NNTP);
  1875. X    if (!isdigit(*machine) ||
  1876. X        (long)(sin.sin_addr.s_addr = inet_addr (machine)) == -1) {
  1877. X        if((hp = gethostbyname (machine)) == NULL) {
  1878. X            fprintf (stderr, "gethostbyname: %s: host unknown\n", machine);
  1879. X            t_close (s);
  1880. X            return (-1);
  1881. X        }
  1882. X        bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  1883. X    }
  1884. X    
  1885. X    /*
  1886. X     * Allocate a t_call structure and initialize it.
  1887. X     * Let t_alloc() initialize the addr structure of the t_call structure.
  1888. X     */
  1889. X    if ((callptr = (struct t_call *) t_alloc (s,T_CALL,T_ADDR)) == NULL){
  1890. X        t_error ("t_alloc");
  1891. X        t_close (s);
  1892. X        return (-1);
  1893. X    }
  1894. X
  1895. X    callptr->addr.maxlen = sizeof (sin);
  1896. X    callptr->addr.len = sizeof (sin);
  1897. X    callptr->addr.buf = (char *) &sin;
  1898. X    callptr->opt.len = 0;            /* no options */
  1899. X    callptr->udata.len = 0;            /* no user data with connect */
  1900. X
  1901. X    /*
  1902. X     * Connect to the server.
  1903. X     */
  1904. X    if (t_connect (s, callptr, (struct t_call *) 0) < 0) {
  1905. X        t_error ("t_connect");
  1906. X        t_close (s);
  1907. X        return (-1);
  1908. X    }
  1909. X
  1910. X    /*
  1911. X     * Now replace the timod module with the tirdwr module so that
  1912. X     * standard read() and write() system calls can be used on the
  1913. X     * descriptor.
  1914. X     */
  1915. X
  1916. X    if (ioctl (s,  I_POP,  (char *) 0) < 0) {
  1917. X        perror ("I_POP(timod)");
  1918. X        t_close (s);
  1919. X        return (-1);
  1920. X    }
  1921. X
  1922. X    if (ioctl (s,  I_PUSH, "tirdwr") < 0) {
  1923. X        perror ("I_PUSH(tirdwr)");
  1924. X        t_close (s);
  1925. X        return (-1);
  1926. X    }
  1927. X    
  1928. X#else /* !TLI */
  1929. X#ifndef EXCELAN
  1930. X    struct    servent *getservbyname(), *sp;
  1931. X    struct    hostent *gethostbyname(), *hp;
  1932. X#ifdef h_addr
  1933. X    int    x = 0;
  1934. X    register char **cp;
  1935. X    static char *alist[1];
  1936. X#endif /* h_addr */
  1937. X    unsigned long inet_addr();
  1938. X    static struct hostent def;
  1939. X    static struct in_addr defaddr;
  1940. X    static char namebuf[256];
  1941. X
  1942. X    if ((sp = getservbyname ("nntp", "tcp")) ==  NULL) {
  1943. X        fprintf (stderr, "nntp/tcp: Unknown service.\n");
  1944. X        return (-1);
  1945. X    }
  1946. X    /* If not a raw ip address, try nameserver */
  1947. X    if (!isdigit(*machine) ||
  1948. X        (long)(defaddr.s_addr = inet_addr (machine)) == -1)
  1949. X        hp = gethostbyname (machine);
  1950. X    else {
  1951. X        /* Raw ip address, fake  */
  1952. X        (void) strcpy (namebuf, machine);
  1953. X        def.h_name = namebuf;
  1954. X#ifdef h_addr
  1955. X        def.h_addr_list = alist;
  1956. X#endif
  1957. X        def.h_addr = (char *) &defaddr;
  1958. X        def.h_length = sizeof (struct in_addr);
  1959. X        def.h_addrtype = AF_INET;
  1960. X        def.h_aliases = 0;
  1961. X        hp = &def;
  1962. X    }
  1963. X    if (hp == NULL) {
  1964. X        fprintf (stderr, "%s: Unknown host.\n", machine);
  1965. X        return (-1);
  1966. X    }
  1967. X
  1968. X    bzero((char *) &sin, sizeof (sin));
  1969. X    sin.sin_family = hp->h_addrtype;
  1970. X    sin.sin_port = sp->s_port;
  1971. X#else /* EXCELAN */
  1972. X    bzero((char *) &sin, sizeof (sin));
  1973. X    sin.sin_family = AF_INET;
  1974. X#endif /* EXCELAN */
  1975. X
  1976. X    /*
  1977. X     * The following is kinda gross.  The name server under 4.3
  1978. X     * returns a list of addresses, each of which should be tried
  1979. X     * in turn if the previous one fails.  However, 4.2 hostent
  1980. X     * structure doesn't have this list of addresses.
  1981. X     * Under 4.3, h_addr is a #define to h_addr_list[0].
  1982. X     * We use this to figure out whether to include the NS specific
  1983. X     * code...
  1984. X     */
  1985. X
  1986. X#ifdef h_addr
  1987. X    /*
  1988. X     * get a socket and initiate connection -- use multiple addresses
  1989. X     */
  1990. X
  1991. X    for (cp = hp->h_addr_list; cp && *cp; cp++) {
  1992. X        s = socket (hp->h_addrtype, SOCK_STREAM, 0);
  1993. X        if (s < 0) {
  1994. X            perror ("socket");
  1995. X            return (-1);
  1996. X        }
  1997. X        bcopy(*cp, (char *) &sin.sin_addr, hp->h_length);
  1998. X        
  1999. X        if (x < 0) {
  2000. X            fprintf (stderr, "trying %s\n", (char *) inet_ntoa (sin.sin_addr));
  2001. X        }
  2002. X        x = connect (s, (struct sockaddr *) &sin, sizeof (sin));
  2003. X        if (x == 0) {
  2004. X            break;
  2005. X        }
  2006. X        fprintf (stderr, "connection to %s: ", (char *) inet_ntoa (sin.sin_addr));
  2007. X        perror ("");
  2008. X        (void) close (s);
  2009. X    }
  2010. X    if (x < 0) {
  2011. X        fprintf (stderr, "giving up...\n");
  2012. X        return (-1);
  2013. X    }
  2014. X#else    /* no name server */
  2015. X#ifdef EXCELAN
  2016. X    if ((s = socket (SOCK_STREAM,(struct sockproto *)NULL,&sin,SO_KEEPALIVE)) < 0) {
  2017. X        /* Get the socket */
  2018. X        perror ("socket");
  2019. X        return (-1);
  2020. X    }
  2021. X    bzero((char *) &sin, sizeof (sin));
  2022. X    sin.sin_family = AF_INET;
  2023. X    sin.sin_port = htons (IPPORT_NNTP);
  2024. X    /* set up addr for the connect */
  2025. X
  2026. X    if ((sin.sin_addr.s_addr = rhost (&machine)) == -1) {
  2027. X        fprintf (stderr, "%s: Unknown host.\n", machine);
  2028. X        return (-1);
  2029. X    }
  2030. X    /* And then connect */
  2031. X
  2032. X    if (connect (s, (struct sockaddr *)&sin) < 0) {
  2033. X        perror ("connect");
  2034. X        (void) close (s);
  2035. X        return (-1);
  2036. X    }
  2037. X#else /* not EXCELAN */
  2038. X    if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  2039. X        perror ("socket");
  2040. X        return (-1);
  2041. X    }
  2042. X
  2043. X    /* And then connect */
  2044. X
  2045. X    bcopy (hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  2046. X    if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
  2047. X        perror ("connect");
  2048. X        (void) close (s);
  2049. X        return (-1);
  2050. X    }
  2051. X
  2052. X#endif /* !EXCELAN */
  2053. X#endif /* !h_addr */
  2054. X#endif /* !TLI */
  2055. X    return (s);
  2056. X#else
  2057. X    return (-1);
  2058. X#endif /* NNTP_ABLE */
  2059. X}
  2060. X
  2061. X#ifdef DECNET
  2062. X/*
  2063. X * get_dnet_socket -- get us a socket connected to the news server.
  2064. X *
  2065. X *    Parameters:    "machine" is the machine the server is running on.
  2066. X *
  2067. X *    Returns:    Socket connected to the news server if
  2068. X *            all is ok, else -1 on error.
  2069. X *
  2070. X *    Side effects:    Connects to server.
  2071. X *
  2072. X *    Errors:        Printed via nerror.
  2073. X */
  2074. X
  2075. Xint get_dnet_socket (machine)
  2076. X    char    *machine;
  2077. X{
  2078. X#ifdef NNTP_ABLE
  2079. X    int    s, area, node;
  2080. X    struct    sockaddr_dn sdn;
  2081. X    struct    nodeent *getnodebyname(), *np;
  2082. X
  2083. X    bzero((char *) &sdn, sizeof (sdn));
  2084. X
  2085. X    switch (s = sscanf (machine, "%d%*[.]%d", &area, &node)) {
  2086. X        case 1: 
  2087. X            node = area;
  2088. X            area = 0;
  2089. X        case 2: 
  2090. X            node += area*1024;
  2091. X            sdn.sdn_add.a_len = 2;
  2092. X            sdn.sdn_family = AF_DECnet;
  2093. X            sdn.sdn_add.a_addr[0] = node % 256;
  2094. X            sdn.sdn_add.a_addr[1] = node / 256;
  2095. X            break;
  2096. X        default:
  2097. X            if ((np = getnodebyname (machine)) == NULL) {
  2098. X                fprintf (stderr, "%s: Unknown host.\n", machine);
  2099. X                return (-1);
  2100. X            } else {
  2101. X                bcopy(np->n_addr, (char *) sdn.sdn_add.a_addr, np->n_length);
  2102. X                sdn.sdn_add.a_len = np->n_length;
  2103. X                sdn.sdn_family = np->n_addrtype;
  2104. X            }
  2105. X            break;
  2106. X    }
  2107. X    sdn.sdn_objnum = 0;
  2108. X    sdn.sdn_flags = 0;
  2109. X    sdn.sdn_objnamel = strlen ("NNTP");
  2110. X    bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  2111. X
  2112. X    if ((s = socket (AF_DECnet, SOCK_STREAM, 0)) < 0) {
  2113. X        nerror ("socket");
  2114. X        return (-1);
  2115. X    }
  2116. X
  2117. X    /* And then connect */
  2118. X
  2119. X    if (connect (s, (struct sockaddr *) &sdn, sizeof (sdn)) < 0) {
  2120. X        nerror ("connect");
  2121. X        close (s);
  2122. X        return (-1);
  2123. X    }
  2124. X
  2125. X    return (s);
  2126. X#else
  2127. X    return (-1);
  2128. X#endif /* NNTP_ABLE */
  2129. X}
  2130. X#endif
  2131. X
  2132. X/*
  2133. X * handle_server_response
  2134. X *
  2135. X *    Print some informative messages based on the server's initial
  2136. X *    response code.  This is here so inews, rn, etc. can share
  2137. X *    the code.
  2138. X *
  2139. X *    Parameters:    "response" is the response code which the
  2140. X *            server sent us, presumably from "server_init",
  2141. X *            above.
  2142. X *            "nntpserver" is the news server we got the
  2143. X *            response code from.
  2144. X *
  2145. X *    Returns:    -1 if the error is fatal (and we should exit).
  2146. X *            0 otherwise.
  2147. X *
  2148. X *    Side effects:    None.
  2149. X */
  2150. X
  2151. Xint handle_server_response (response, nntpserver)
  2152. X    int    response;
  2153. X    char    *nntpserver;
  2154. X{
  2155. X#ifdef NNTP_ABLE
  2156. X    switch (response) {
  2157. X        case OK_NOPOST:        /* fall through */
  2158. X                printf ("NOTE: This machine does not have permission to post articles.\n");
  2159. X            printf ("      Please don't waste your time trying.\n\n");
  2160. X
  2161. X        case OK_CANPOST:
  2162. X            return (0);
  2163. X            break;
  2164. X
  2165. X        case ERR_ACCESS:
  2166. X            printf ("This machine does not have permission to use the %s news server.\n", nntpserver);
  2167. X            return (-1);
  2168. X            break;
  2169. X
  2170. X        default:
  2171. X            printf ("Unexpected response code from %s news server: %d\n",
  2172. X                nntpserver, response);
  2173. X            return (-1);
  2174. X            break;
  2175. X    }
  2176. X    /*NOTREACHED*/
  2177. X#else
  2178. X    return (-1);
  2179. X#endif /* NNTP_ABLE */
  2180. X}
  2181. X
  2182. X/*
  2183. X * put_server -- send a line of text to the server, terminating it
  2184. X * with CR and LF, as per ARPA standard.
  2185. X *
  2186. X *    Parameters:    "string" is the string to be sent to the
  2187. X *            server.
  2188. X *
  2189. X *    Returns:    Nothing.
  2190. X *
  2191. X *    Side effects:    Talks to the server.
  2192. X *
  2193. X *    Note:    This routine flushes the buffer each time
  2194. X *            it is called.  For large transmissions
  2195. X *            (i.e., posting news) don't use it.  Instead,
  2196. X *            do the fprintf's yourself, and then a final
  2197. X *            fflush.
  2198. X */
  2199. X
  2200. Xvoid put_server (string)
  2201. X    char *string;
  2202. X{
  2203. X#ifdef NNTP_ABLE
  2204. X    fprintf (ser_wr_fp, "%s\r\n", string);
  2205. X    (void) fflush (ser_wr_fp);
  2206. X#endif /* NNTP_ABLE */
  2207. X}
  2208. X
  2209. X/*
  2210. X * get_server -- get a line of text from the server.  Strips
  2211. X * CR's and LF's.
  2212. X *
  2213. X *    Parameters:    "string" has the buffer space for the
  2214. X *            line received.
  2215. X *            "size" is the size of the buffer.
  2216. X *
  2217. X *    Returns:    -1 on error, 0 otherwise.
  2218. X *
  2219. X *    Side effects:    Talks to server, changes contents of "string".
  2220. X */
  2221. X
  2222. Xint get_server (string, size)
  2223. X    char    *string;
  2224. X    int    size;
  2225. X{
  2226. X#ifdef NNTP_ABLE
  2227. X    register char *cp;
  2228. X
  2229. X    if (fgets (string, size, ser_rd_fp) == NULL) {
  2230. X        return (-1);
  2231. X    }
  2232. X
  2233. X    if ((cp = (char *) index(string, '\r')) != NULL) {
  2234. X        *cp = '\0';
  2235. X    } else if ((cp = (char *) index(string, '\n')) != NULL) {
  2236. X        *cp = '\0';
  2237. X    }
  2238. X
  2239. X    return (0);
  2240. X#else
  2241. X    return (-1);
  2242. X#endif /* NNTP_ABLE */
  2243. X}
  2244. X
  2245. X/*
  2246. X * close_server -- close the connection to the server, after sending
  2247. X *        the "quit" command.
  2248. X *
  2249. X *    Parameters:    None.
  2250. X *
  2251. X *    Returns:    Nothing.
  2252. X *
  2253. X *    Side effects:    Closes the connection with the server.
  2254. X *            You can't use "put_server" or "get_server"
  2255. X *            after this routine is called.
  2256. X */
  2257. X
  2258. Xvoid close_server ()
  2259. X{
  2260. X#ifdef NNTP_ABLE
  2261. X    char    ser_line[256];
  2262. X
  2263. X    if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  2264. X        return;
  2265. X
  2266. X    put_server ("QUIT");
  2267. X    (void) get_server (ser_line, sizeof (ser_line));
  2268. X
  2269. X    (void) fclose (ser_wr_fp);
  2270. X    (void) fclose (ser_rd_fp);
  2271. X#endif /* NNTP_ABLE */
  2272. X}
  2273. X
  2274. X#endif /* CDROM_ABLE */
  2275. X
  2276. END_OF_FILE
  2277.   if test 14736 -ne `wc -c <'nntplib.c'`; then
  2278.     echo shar: \"'nntplib.c'\" unpacked with wrong size!
  2279.   fi
  2280.   # end of 'nntplib.c'
  2281. fi
  2282. echo shar: End of archive 10 \(of 15\).
  2283. cp /dev/null ark10isdone
  2284. MISSING=""
  2285. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
  2286.     if test ! -f ark${I}isdone ; then
  2287.     MISSING="${MISSING} ${I}"
  2288.     fi
  2289. done
  2290. if test "${MISSING}" = "" ; then
  2291.     echo You have unpacked all 15 archives.
  2292.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2293. else
  2294.     echo You still must unpack the following archives:
  2295.     echo "        " ${MISSING}
  2296. fi
  2297. exit 0
  2298. exit 0 # Just in case...
  2299.