home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / tin / part11 / open.c < prev   
C/C++ Source or Header  |  1992-05-20  |  14KB  |  707 lines

  1. /*
  2.  *  Project   : tin - a threaded Netnews reader
  3.  *  Module    : open.c
  4.  *  Author    : I.Lea & R.Skrenta
  5.  *  Created   : 01-04-91
  6.  *  Updated   : 12-05-92
  7.  *  Notes     : reads news locally (ie. /usr/spool/news) or via NNTP
  8.  *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  9.  *              You may  freely  copy or  redistribute  this software,
  10.  *              so  long as there is no profit made from its use, sale
  11.  *              trade or  reproduction.  You may not change this copy-
  12.  *              right notice, and it must be included in any copy made
  13.  */
  14.  
  15. #include    "tin.h"
  16. #include    "nntplib.h"
  17.  
  18. /*
  19.  * Directory handling code - Hopefully one of these is right for you. 
  20.  */
  21. #ifdef BSD
  22. #    ifdef sinix
  23. #        include <dir.h>
  24. #    else
  25. #        include <sys/dir.h>
  26. #    endif
  27. #    define        DIR_BUF        struct direct
  28. #    define        D_LENGTH    d_namlen
  29. #endif
  30. #ifdef M_XENIX
  31. #    include <sys/ndir.h>
  32. #    define        DIR_BUF        struct direct
  33. #    define        D_LENGTH    d_namlen
  34. #endif
  35. #ifndef DIR_BUF
  36. #    include    <dirent.h>
  37. #    define        DIR_BUF        struct dirent
  38. #    define        D_LENGTH    d_reclen
  39. #endif
  40.  
  41. int nntp_codeno = 0;
  42.  
  43. #ifdef NNTP_ABLE
  44. int compiled_with_nntp = TRUE;        /* used in mail_bug_report() info */
  45. #else
  46. int compiled_with_nntp = FALSE;
  47. #endif
  48.  
  49. #ifdef NO_POSTING
  50. int    can_post = FALSE;
  51. #else
  52. int    can_post = TRUE;
  53. #endif
  54.  
  55. char server_name[LEN];
  56.  
  57.  
  58. void nntp_open ()
  59. {
  60. #ifdef NNTP_ABLE    
  61.     char *server;
  62.     int ret;
  63.  
  64.     if (read_news_via_nntp) {
  65.         debug_nntp ("nntp_open", "BEGIN");
  66.  
  67.         if (nntp_server[0]) {
  68.             server = nntp_server;
  69.         } else {
  70.             server = getserverbyfile (NNTP_SERVER_FILE);
  71.         }
  72.  
  73.         if (server == (char *) 0) {
  74.             error_message (txt_cannot_get_nntp_server_name, "");
  75.             error_message (txt_server_name_in_file_env_var, NNTP_SERVER_FILE);
  76.             exit(1);
  77.         }
  78.  
  79.         if (update == FALSE) {
  80.             sprintf (msg, txt_connecting, server);
  81.             wait_message (msg);
  82.         }
  83.         
  84.         debug_nntp ("nntp_open", server);
  85.  
  86.         ret = server_init (server);
  87.         if (update == FALSE) {
  88.             fputc ('\n', stdout);
  89.         }
  90.  
  91.         debug_nntp_respcode (ret);
  92.  
  93.         switch (ret) {
  94.         case OK_CANPOST:
  95. #ifndef NO_POSTING        
  96.             can_post = TRUE;
  97. #endif            
  98.             break;
  99.  
  100.         case OK_NOPOST:
  101.             can_post = FALSE;
  102.             break;    
  103.  
  104.         case -1:
  105.             error_message (txt_failed_to_connect_to_server, server);
  106.             exit (1);
  107.  
  108.         default:
  109.             sprintf (msg, "%s: %s", progname, nntp_respcode (ret));
  110.             error_message (msg, "");
  111.             exit (1);
  112.         }
  113.  
  114.         /*
  115.          * Find out if NNTP supports my XINDEX & XUSER commands
  116.          */
  117.         debug_nntp ("nntp_open", "xindex");
  118.         put_server ("xindex");    
  119.         if (get_respcode () != ERR_COMMAND) {
  120.             xindex_supported = TRUE;
  121.         }
  122.         debug_nntp ("nntp_open", "xuser");
  123.         put_server ("xuser");    
  124.         if (get_respcode () != ERR_COMMAND) {
  125.             xuser_supported = TRUE;
  126.         }
  127.         
  128.         /*
  129.          * If INN NNTP & XINDEX not supported switch to mode reader
  130.          */
  131.         if (! xindex_supported) {
  132.             debug_nntp ("nntp_open", "mode reader");
  133.             put_server ("mode reader");    
  134.             if (get_respcode () != ERR_COMMAND) {
  135.                 inn_nntp_server = TRUE;
  136.             }
  137.         }
  138.     }
  139.     /*
  140.      * Find out if NNTP supports SPOOLDIR command
  141.      */
  142.     get_spooldir ();
  143. #endif    
  144. }
  145.  
  146.  
  147. void nntp_close ()
  148. {
  149. #ifdef NNTP_ABLE
  150.     if (read_news_via_nntp) {
  151.         debug_nntp ("nntp_close", "END");
  152.         close_server ();
  153.     }
  154. #endif    
  155. }
  156.  
  157.  
  158. FILE *open_active_fp ()
  159. {
  160.     if (read_news_via_nntp) {
  161. #ifdef NNTP_ABLE
  162.         put_server ("list");
  163.         if (get_respcode () != OK_GROUPS) {
  164.             debug_nntp ("open_active_fp", "NOT_OK");
  165.             return (FILE *) 0;
  166.         }
  167.         debug_nntp ("open_active_fp", "OK");
  168.         return nntp_to_fp ();
  169. #else
  170.         return (FILE *) 0;
  171. #endif        
  172.     } else {
  173.         return fopen (active_file, "r");
  174.     }
  175. }
  176.  
  177.  
  178. FILE *open_subscription_fp ()
  179. {
  180.     if (read_news_via_nntp) {
  181. #ifdef NNTP_ABLE
  182.         put_server ("list subscriptions");
  183.         if (get_respcode () != OK_GROUPS) {
  184.             debug_nntp ("open_subscription_fp", "NOT_OK");
  185.             return (FILE *) 0;
  186.         }
  187.         debug_nntp ("open_subscription_fp", "OK");
  188.         return nntp_to_fp ();
  189. #else
  190.         return (FILE *) 0;
  191. #endif        
  192.     } else {
  193.         return fopen (subscriptions_file, "r");
  194.     }
  195. }
  196.  
  197.  
  198. FILE *open_index_fp (group_name)
  199.     char *group_name;
  200. {
  201.     char line[NNTP_STRLEN];
  202.     extern char index_file[PATH_LEN];
  203.  
  204.     find_index_file (group_name);
  205.     
  206.     if (read_news_via_nntp && xindex_supported) {
  207.         sprintf (line, "xindex %s", group_name);
  208.         debug_nntp ("open_index_fp", line);
  209.         put_server (line);
  210.         if (get_respcode () != OK_XINDEX) {
  211.             debug_nntp ("open_index_fp", "NOT_OK");
  212.             return (FILE *) 0;
  213.         }
  214.         debug_nntp ("open_index_fp", "OK");
  215.         return nntp_to_fp ();
  216.     } else {
  217.         return fopen (index_file, "r");
  218.     }
  219. }
  220.  
  221.  
  222. FILE *open_art_fp (group_path, art)
  223.     char *group_path;
  224.     long art;
  225. {
  226.     char buf[LEN];
  227.     int respcode;
  228.     struct stat sb;
  229.     extern long note_size;
  230.  
  231.     if (read_news_via_nntp) {
  232. #ifdef NNTP_ABLE
  233.         sprintf (buf, "article %ld", art);
  234.         debug_nntp ("open_art_fp", buf);
  235.         put_server (buf);
  236.         if ((respcode = get_respcode ()) != OK_ARTICLE) {
  237.             error_message ("%s", nntp_respcode (respcode));
  238.             debug_nntp ("open_art_fp", buf);
  239.             return (FILE *) 0;
  240.         }
  241.  
  242.         debug_nntp ("open_art_fp", "OK");
  243.  
  244.         return nntp_to_fp ();
  245. #else
  246.         return (FILE *) 0;
  247. #endif
  248.     } else {
  249.         sprintf (buf, "%s/%s/%ld", spooldir, group_path, art);
  250.  
  251.         if (stat (buf, &sb) < 0) {
  252.             note_size = 0;
  253.         } else {
  254.             note_size = sb.st_size;
  255.         }
  256.         return fopen (buf, "r");
  257.     }
  258. }
  259.  
  260.  
  261. FILE *open_header_fp (group_path, art)
  262.     char *group_path;
  263.     long art;
  264. {
  265.     char buf[LEN];
  266.     
  267.     if (read_news_via_nntp) {
  268. #ifdef NNTP_ABLE    
  269.         sprintf(buf, "head %ld", art);
  270.         
  271.         debug_nntp ("open_header_fp", buf);
  272.  
  273.         put_server (buf);
  274.         if (get_respcode () != OK_HEAD) {
  275.             debug_nntp ("open_header_fp", "NOT_OK_HEAD");
  276.             return (FILE *) 0;
  277.         }
  278.  
  279.         debug_nntp ("open_header_fp", "OK_HEAD");
  280.  
  281.         return nntp_to_fp ();
  282. #else
  283.         return (FILE *) 0;
  284. #endif        
  285.     } else {
  286.         sprintf (buf, "%s/%s/%ld", spooldir, group_path, art);
  287.         return fopen (buf, "r");
  288.     }
  289. }
  290.  
  291. /*
  292.  *  Longword comparison routine for the qsort()
  293.  */
  294.  
  295. int base_comp (p1, p2)
  296.     char *p1;
  297.     char *p2;
  298. {
  299.     long *a = (long *) p1;
  300.     long *b = (long *) p2;
  301.  
  302.     if (*a < *b)
  303.         return -1;
  304.     if (*a > *b)
  305.         return 1;
  306.     return 0;
  307. }
  308.  
  309.  
  310. /*
  311.  *  Read the article numbers existing in a group's spool directory
  312.  *  into base[] and sort them.  top_base is one past top.
  313.  */
  314.  
  315. void setup_base (group, group_path)
  316.     char *group;
  317.     char *group_path;
  318. {
  319.     char buf[LEN];
  320. #ifdef NNTP_ABLE
  321.     char line[NNTP_STRLEN];
  322. #endif
  323.     DIR *d;
  324.     DIR_BUF *e;
  325.     long art, start, last, dummy, count;
  326.  
  327.     top_base = 0;
  328.  
  329.     if (read_news_via_nntp) {
  330.  
  331. #ifdef NNTP_ABLE
  332.         sprintf (buf, "group %s", group);
  333.  
  334.         debug_nntp ("setup_base", buf);
  335.         
  336.         put_server (buf);
  337.  
  338.         if (get_server (line, NNTP_STRLEN) == -1) {
  339.             error_message (txt_connection_to_server_broken, "");
  340.             tin_done (1);
  341.         }
  342.  
  343.         if (atoi(line) != OK_GROUP) {
  344.             debug_nntp ("setup_base", "NOT_OK");
  345.             return;
  346.         }
  347.  
  348.         debug_nntp ("setup_base", line);
  349.  
  350.         sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last);
  351.         if (last - count > start) {
  352.             start = last - count;
  353.         }
  354.  
  355.         while (start <= last) {
  356.             if (top_base >= max_art) {
  357.                 expand_art();
  358.             }
  359.             base[top_base++] = start++;
  360.         }
  361. #else
  362.         return; 
  363. #endif
  364.     } else {
  365.         sprintf (buf, "%s/%s", spooldir, group_path);
  366.  
  367.         if (access (buf, 4) != 0) {
  368.             return;
  369.         }
  370.  
  371.         d = opendir (buf);
  372.         if (d != NULL) {
  373.             while ((e = readdir (d)) != NULL) {
  374.                 art = my_atol (e->d_name, (int) e->D_LENGTH);
  375.                 if (art >= 0) {
  376.                     if (top_base >= max_art)
  377.                         expand_art ();
  378.                     base[top_base++] = art;
  379.                 }
  380.             }
  381.             closedir (d);
  382.             qsort ((char *) base, top_base, sizeof (long), base_comp);
  383.         }
  384.     }
  385. }
  386.  
  387. /*
  388.  *  get a response code from the server and return it to the caller
  389.  */
  390.  
  391. int get_respcode ()
  392. {
  393. #ifdef NNTP_ABLE
  394.     char line[NNTP_STRLEN];
  395.  
  396.     if (get_server (line, NNTP_STRLEN) == -1) {
  397.         error_message (txt_connection_to_server_broken, "");
  398.         tin_done (1);
  399.     }
  400.  
  401.     debug_nntp ("get_respcode", line);
  402.     
  403.     return atoi (line);
  404. #else
  405.     return (0);
  406. #endif
  407. }
  408.  
  409.  
  410. int stuff_nntp (fnam)
  411.     char *fnam;
  412. {
  413. #ifdef NNTP_ABLE
  414.     FILE *fp;
  415.     char line[NNTP_STRLEN];
  416.     extern char *mktemp ();
  417.     struct stat sb;
  418.     extern long note_size;
  419.  
  420.     strcpy (fnam, "/tmp/tin_nntpXXXXXX");
  421.     mktemp (fnam);
  422.  
  423.     if ((fp = fopen (fnam, "w")) == (FILE *) 0) {
  424.         perror_message (txt_stuff_nntp_cannot_open, fnam);
  425.         return FALSE;
  426.     }
  427.  
  428.     while (1) {
  429.         if (get_server (line, NNTP_STRLEN) == -1) {
  430.             error_message (txt_connection_to_server_broken, "");
  431.             tin_done (1);
  432.         }
  433.  
  434.         debug_nntp ("stuff_nntp", line);
  435.         
  436.         if (strcmp (line, ".") == 0)
  437.             break;            /* end of text */
  438.         strcat (line, "\n");
  439.         if (line[0] == '.')        /* reduce leading .'s */
  440.             fputs (&line[1], fp);
  441.         else
  442.             fputs (line, fp);
  443.     }
  444.     fclose (fp);
  445.  
  446.     if (stat (fnam, &sb) < 0)
  447.         note_size = 0;
  448.     else
  449.         note_size = sb.st_size;
  450.  
  451.     return TRUE;
  452. #else
  453.     return TRUE;
  454. #endif
  455. }
  456.  
  457.  
  458. FILE *nntp_to_fp ()
  459. {
  460. #ifdef NNTP_ABLE
  461.     char fnam[LEN];
  462.     FILE *fp = (FILE *) 0;
  463.     
  464.     if (! stuff_nntp (fnam)) {
  465.         debug_nntp ("nntp_to_fp", "! stuff_nntp()");
  466.         return (FILE *) 0;
  467.     }
  468.  
  469.     if ((fp = fopen (fnam, "r")) == (FILE *) 0) {
  470.         perror_message (txt_nntp_to_fp_cannot_reopen, fnam);
  471.         return (FILE *) 0;
  472.     }
  473.     
  474.     unlink (fnam);
  475.     return fp;
  476. #else
  477.     return (FILE *) 0;
  478. #endif
  479. }
  480.  
  481. /*
  482.  * Log user info to local file or NNTP logfile
  483.  */
  484.  
  485. void log_user ()
  486. {
  487.     char buf[32], *ptr;
  488.     char line[NNTP_STRLEN];
  489. #ifdef LOG_USER
  490.     FILE *fp;
  491.     long epoch;
  492. #endif
  493.     extern struct passwd *myentry;
  494.  
  495.     my_strncpy (buf, myentry->pw_gecos, sizeof (buf)-1);
  496.  
  497.     if (read_news_via_nntp && xuser_supported) {
  498.         if ((ptr = (char *) strchr(buf, ','))) {
  499.             *ptr = '\0';
  500.         }
  501.         sprintf (line, "xuser %s (%s)", myentry->pw_name, buf);
  502.  
  503.         debug_nntp ("log_user", line);
  504.         put_server (line);
  505.     } else {
  506. #ifdef LOG_USER
  507.         if ((fp = fopen (LOG_USER_FILE, "a+")) != (FILE *) 0) {
  508.             time (&epoch);
  509.             fprintf (fp, "%s%d: %-32s (%-8s) %s", VERSION, PATCHLEVEL,
  510.                     buf, myentry->pw_name, ctime (&epoch));
  511.             fclose (fp);
  512.             chmod (LOG_USER_FILE, 0666);
  513.         }    
  514. #endif
  515.     }
  516. }
  517.  
  518. /*
  519.  * NNTP strings for get_respcode()
  520.  */
  521.  
  522. char *nntp_respcode (respcode)
  523.     int respcode;
  524. {
  525. #ifdef NNTP_ABLE
  526.  
  527.     static char *text;
  528.     
  529.     switch (respcode) {
  530.         case 0:
  531.             text = "";
  532.             break;
  533.         case INF_HELP:
  534.             text = "100  Help text on way";
  535.             break;
  536.         case INF_AUTH:
  537.             text = "180  Authorization capabilities";
  538.             break;
  539.         case INF_DEBUG:
  540.             text = "199  Debug output";
  541.             break;
  542.         case OK_CANPOST:
  543.             text = "200  Hello; you can post";
  544.             break;
  545.         case OK_NOPOST:
  546.             text = "201  Hello; you can't post";
  547.             break;
  548.         case OK_SLAVE:
  549.             text = "202  Slave status noted";
  550.             break;
  551.         case OK_GOODBYE:
  552.             text = "205  Closing connection";
  553.             break;
  554.         case OK_GROUP:
  555.             text = "211  Group selected";
  556.             break;
  557.         case OK_GROUPS:
  558.             text = "215  Newsgroups follow";
  559.             break;
  560.         case OK_XINDEX:
  561.             text = "218  Group index file follows";
  562.             break;
  563.         case OK_ARTICLE:
  564.             text = "220  Article (head & body) follows";
  565.             break;
  566.         case OK_HEAD:
  567.             text = "221  Head follows";
  568.             break;
  569.         case OK_BODY:
  570.             text = "222  Body follows";
  571.             break;
  572.         case OK_NOTEXT:
  573.             text = "223  No text sent -- stat, next, last";
  574.             break;
  575.         case OK_NEWNEWS:
  576.             text = "230  New articles by message-id follow";
  577.             break;
  578.         case OK_NEWGROUPS:
  579.             text = "231  New newsgroups follow";
  580.             break;
  581.         case OK_XFERED:
  582.             text = "235  Article transferred successfully";
  583.             break;
  584.         case OK_POSTED:
  585.             text = "240  Article posted successfully";
  586.             break;
  587.         case OK_AUTHSYS:
  588.             text = "280  Authorization system ok";
  589.             break;
  590.         case OK_AUTH:
  591.             text = "281  Authorization (user/pass) ok";
  592.             break;
  593.         case OK_BIN:
  594.             text = "282  binary data follows";
  595.             break;
  596.         case OK_SPLIST:
  597.             text = "283  spooldir list follows";
  598.             break;
  599.         case OK_SPSWITCH:
  600.             text = "284  Switching to a different spooldir";
  601.             break;
  602.         case OK_SPNOCHANGE:
  603.             text = "285  Still using same spooldir";
  604.             break;
  605.         case OK_SPLDIRCUR:
  606.             text = "286  Current spooldir";
  607.             break;
  608.         case OK_SPLDIRAVL:
  609.             text = "287  Available spooldir";
  610.             break;
  611.         case OK_SPLDIRERR:
  612.             text = "288  Unavailable spooldir or invalid entry";
  613.             break;
  614.         case CONT_XFER:
  615.             text = "335  Continue to send article";
  616.             break;
  617.         case CONT_POST:
  618.             text = "340  Continue to post article";
  619.             break;
  620.         case NEED_AUTHINFO:
  621.             text = "380  authorization is required";
  622.             break;
  623.         case NEED_AUTHDATA:
  624.             text = "381  <type> authorization data required";
  625.             break;
  626.         case ERR_GOODBYE:
  627.             text = "400  Have to hang up for some reason";
  628.             break;
  629.         case ERR_NOGROUP:
  630.             text = "411  No such newsgroup";
  631.             break;
  632.         case ERR_NCING:
  633.             text = "412  Not currently in newsgroup";
  634.             break;
  635.         case ERR_XINDEX:
  636.             text = "418  No index file for this group";
  637.             break;
  638.         case ERR_NOCRNT:
  639.             text = "420  No current article selected";
  640.             break;
  641.         case ERR_NONEXT:
  642.             text = "421  No next article in this group";
  643.             break;
  644.         case ERR_NOPREV:
  645.             text = "422  No previous article in this group";
  646.             break;
  647.         case ERR_NOARTIG:
  648.             text = "423  No such article in this group";
  649.             break;
  650.         case ERR_NOART:
  651.             text = "430  No such article at all";
  652.             break;
  653.         case ERR_GOTIT:
  654.             text = "435  Already got that article, don't send";
  655.             break;
  656.         case ERR_XFERFAIL:
  657.             text = "436  Transfer failed";
  658.             break;
  659.         case ERR_XFERRJCT:
  660.             text = "437  Article rejected, don't resend";
  661.             break;
  662.         case ERR_NOPOST:
  663.             text = "440  Posting not allowed";
  664.             break;
  665.         case ERR_POSTFAIL:
  666.             text = "441  Posting failed";
  667.             break;
  668.         case ERR_NOAUTH:
  669.             text = "480  authorization required for command";
  670.             break;
  671.         case ERR_AUTHSYS:
  672.             text = "481  Authorization system invalid";
  673.             break;
  674.         case ERR_AUTHREJ:
  675.             text = "482  Authorization data rejected";
  676.             break;
  677.         case ERR_INVALIAS:
  678.             text = "483  Invalid alias on spooldir cmd";
  679.             break;
  680.         case ERR_INVNOSPDIR:
  681.             text = "484  No spooldir file found";
  682.             break;
  683.         case ERR_COMMAND:
  684.             text = "500  Command not recognized";
  685.             break;
  686.         case ERR_CMDSYN:
  687.             text = "501  Command syntax error";
  688.             break;
  689.         case ERR_ACCESS:
  690.             text = "502  Access to server denied";
  691.             break;
  692.         case ERR_FAULT:
  693.             text = "503  Program fault, command not performed";
  694.             break;
  695.         case ERR_AUTHBAD:
  696.             text = "580  Authorization Failed";
  697.             break;
  698.         default:
  699.             text = "Unknown NNTP response code";
  700.             break;
  701.     }
  702.     return (text);
  703. #else
  704.     return ("");
  705. #endif
  706. }
  707.