"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/xref.c" (12 Oct 2016, 12946 Bytes) of archive /linux/misc/tin-2.4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xref.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.0_vs_2.4.1.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : xref.c
    4  *  Author    : I. Lea & H. Brugge
    5  *  Created   : 1993-07-01
    6  *  Updated   : 2016-06-02
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1993-2017 Iain Lea <iain@bricbrac.de>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote
   21  *    products derived from this software without specific prior written
   22  *    permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 
   38 #ifndef TIN_H
   39 #   include "tin.h"
   40 #endif /* !TIN_H */
   41 #ifndef NEWSRC_H
   42 #   include "newsrc.h"
   43 #endif /* !NEWSRC_H */
   44 
   45 /*
   46  * local prototypes
   47  */
   48 static FILE *open_overview_fmt_fp(void);
   49 
   50 struct t_overview_fmt *ofmt;
   51 t_bool expensive_over_parse = FALSE;
   52 
   53 /*
   54  * Open the NEWSLIBDIR/overview.fmt file locally or send LIST OVERVIEW.FMT
   55  */
   56 static FILE *
   57 open_overview_fmt_fp(
   58     void)
   59 {
   60 #ifdef NNTP_ABLE
   61     if (read_news_via_nntp && !read_saved_news) {
   62         if (!*nntp_caps.over_cmd)
   63             return (FILE *) 0;
   64 
   65         if ((nntp_caps.type == CAPABILITIES && nntp_caps.list_overview_fmt) || nntp_caps.type != CAPABILITIES)
   66             return (nntp_command("LIST OVERVIEW.FMT", OK_GROUPS, NULL, 0));
   67 
   68         return (FILE *) 0;
   69     }
   70 #endif /* NNTP_ABLE */
   71     return (fopen(overviewfmt_file, "r"));
   72 }
   73 
   74 
   75 /*
   76  * Read overview.fmt file to check if Xref:full is enabled/disabled
   77  */
   78 t_bool
   79 overview_xref_support(
   80     void)
   81 {
   82     FILE *fp;
   83     char *ptr;
   84     char *p, *q;
   85     t_bool supported = FALSE;
   86     size_t res_fields = 9; /* initial number of overview fields */
   87     size_t fields = 0;
   88     size_t i;
   89 
   90     ofmt[0].type = OVER_T_INT;
   91     ofmt[0].name = my_strdup("Artnum:");
   92 
   93     if ((fp = open_overview_fmt_fp()) != NULL) {
   94         while ((ptr = tin_fgets(fp, FALSE)) != NULL) {
   95             if (*ptr == '#' || *ptr == '\n')    /* skip comments and empty lines */
   96                 continue;
   97 
   98 #if defined(DEBUG) && defined(NNTP_ABLE)
   99             if (debug & DEBUG_NNTP)
  100                 debug_print_file("NNTP", "<<<%s%s", logtime(), ptr);
  101 #endif /* DEBUG && NNTP_ABLE */
  102 
  103             fields++;
  104 
  105             /* expand overview fmt array */
  106             if (fields >= res_fields) {
  107                 res_fields <<= 1;
  108                 ofmt = my_realloc(ofmt, sizeof(struct t_overview_fmt) * res_fields);
  109             }
  110 
  111             if ((p = strchr(ptr, ':'))) {
  112                 if (p == ptr) { /* metadata items start with : */
  113                     /* currently there is only :lines ands :bytes reserved */
  114                     if (!strcasecmp(ptr, ":lines")) {
  115                         ofmt[fields].type = OVER_T_INT;
  116                         ofmt[fields].name = my_strdup("Lines:");
  117                         if (fields != 7) {
  118                             expensive_over_parse = TRUE;
  119 #ifdef DEBUG
  120                             if (debug & DEBUG_NNTP)
  121                                 debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 7);
  122 #endif /* DEBUG */
  123                         }
  124                         continue;
  125                     }
  126 
  127                     if (!strcasecmp(ptr, ":bytes")) {
  128                         ofmt[fields].type = OVER_T_INT;
  129                         ofmt[fields].name = my_strdup("Bytes:");
  130                         if (fields != 6) {
  131                             expensive_over_parse = TRUE;
  132 #ifdef DEBUG
  133                             if (debug & DEBUG_NNTP)
  134                                 debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 6);
  135 #endif /* DEBUG */
  136                         }
  137                         continue;
  138                     }
  139                     /* unknown metadata item */
  140                 }
  141 
  142                 /* non metadata items end with : or :full */
  143                 /* optional items require :full */
  144                 if (!strcasecmp(p, ":full")) {
  145                     ofmt[fields].type = OVER_T_FSTRING;
  146                     q = strchr(p, ':');
  147                     *(++q) = '\0';
  148                     ofmt[fields].name = my_strdup(ptr);
  149                     if (fields < 7) {
  150                         expensive_over_parse = TRUE;
  151 #ifdef DEBUG
  152                         if (debug & DEBUG_NNTP)
  153                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected > %d", ptr, fields, 7);
  154 #endif /* DEBUG */
  155                     }
  156 #ifdef DEBUG
  157                     else {
  158                         if (debug & DEBUG_NNTP)
  159                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d", ptr, fields);
  160                     }
  161 #endif /* DEBUG */
  162 
  163                     continue;
  164                 }
  165 
  166                 /* madatory items */
  167                 if (!strcasecmp(ptr, "Subject:")) {
  168                     ofmt[fields].type = OVER_T_STRING;
  169                     ofmt[fields].name = my_strdup(ptr);
  170                     if (fields != 1) {
  171                         expensive_over_parse = TRUE;
  172 #ifdef DEBUG
  173                         if (debug & DEBUG_NNTP)
  174                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 1);
  175 #endif /* DEBUG */
  176                     }
  177                     continue;
  178                 }
  179 
  180                 if (!strcasecmp(ptr, "From:")) {
  181                     ofmt[fields].type = OVER_T_STRING;
  182                     ofmt[fields].name = my_strdup(ptr);
  183                     if (fields != 2) {
  184                         expensive_over_parse = TRUE;
  185 #ifdef DEBUG
  186                         if (debug & DEBUG_NNTP)
  187                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 2);
  188 #endif /* DEBUG */
  189                     }
  190                     continue;
  191                 }
  192 
  193                 if (!strcasecmp(ptr, "Date:")) {
  194                     ofmt[fields].type = OVER_T_STRING;
  195                     ofmt[fields].name = my_strdup(ptr);
  196                     if (fields != 3) {
  197                         expensive_over_parse = TRUE;
  198 #ifdef DEBUG
  199                         if (debug & DEBUG_NNTP)
  200                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 3);
  201 #endif /* DEBUG */
  202                     }
  203                     continue;
  204                 }
  205 
  206                 if (!strcasecmp(ptr, "Message-ID:")) {
  207                     ofmt[fields].type = OVER_T_STRING;
  208                     ofmt[fields].name = my_strdup(ptr);
  209                     if (fields != 4) {
  210                         expensive_over_parse = TRUE;
  211 #ifdef DEBUG
  212                         if (debug & DEBUG_NNTP)
  213                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 4);
  214 #endif /* DEBUG */
  215                     }
  216                     continue;
  217                 }
  218 
  219                 if (!strcasecmp(ptr, "References:")) {
  220                     ofmt[fields].type = OVER_T_STRING;
  221                     ofmt[fields].name = my_strdup(ptr);
  222                     if (fields != 5) {
  223                         expensive_over_parse = TRUE;
  224 #ifdef DEBUG
  225                         if (debug & DEBUG_NNTP)
  226                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 5);
  227 #endif /* DEBUG */
  228                     }
  229                     continue;
  230                 }
  231 
  232                 if (!strcasecmp(ptr, "Bytes:")) {
  233                     ofmt[fields].type = OVER_T_INT;
  234                     ofmt[fields].name = my_strdup(ptr);
  235                     if (fields != 6) {
  236                         expensive_over_parse = TRUE;
  237 #ifdef DEBUG
  238                         if (debug & DEBUG_NNTP)
  239                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 6);
  240 #endif /* DEBUG */
  241                     }
  242                     continue;
  243                 }
  244 
  245                 if (!strcasecmp(ptr, "Lines:")) {
  246                     ofmt[fields].type = OVER_T_INT;
  247                     ofmt[fields].name = my_strdup(ptr);
  248                     if (fields != 7) {
  249                         expensive_over_parse = TRUE;
  250 #ifdef DEBUG
  251                         if (debug & DEBUG_NNTP)
  252                             debug_print_file("NNTP", "OVERVIEW.FMT: %s at position %d expected %d", ptr, fields, 7);
  253 #endif /* DEBUG */
  254                     }
  255                     continue;
  256                 }
  257             }
  258             /* bogus entry */
  259             ofmt[fields].type = OVER_T_ERROR;
  260             ofmt[fields].name = my_strdup(ptr);
  261         }
  262         TIN_FCLOSE(fp);
  263     }
  264 
  265     fields++;
  266     /* resize */
  267     ofmt = my_realloc(ofmt, sizeof(struct t_overview_fmt) * (fields + 1));
  268 
  269     /* end marker */
  270     ofmt[fields].type = OVER_T_ERROR;
  271     ofmt[fields].name = NULL;
  272 
  273     if (fields < 2) {
  274 #ifdef DEBUG
  275         if (debug & DEBUG_NNTP)
  276             debug_print_file("NNTP", fp ? "OVERVIEW.FMT: Empty response - using safe defaults" : "OVERVIEW.FMT: not advertized - using safe defaults");
  277 #endif /* DEBUG */
  278         ofmt = my_realloc(ofmt, sizeof(struct t_overview_fmt) * (8 + 1));
  279         ofmt[1].type = OVER_T_STRING;
  280         ofmt[1].name = my_strdup("Subject:");
  281         ofmt[2].type = OVER_T_STRING;
  282         ofmt[2].name = my_strdup("From:");
  283         ofmt[3].type = OVER_T_STRING;
  284         ofmt[3].name = my_strdup("Date:");
  285         ofmt[4].type = OVER_T_STRING;
  286         ofmt[4].name = my_strdup("Message-ID:");
  287         ofmt[5].type = OVER_T_STRING;
  288         ofmt[5].name = my_strdup("References:");
  289         ofmt[6].type = OVER_T_INT;
  290         ofmt[6].name = my_strdup("Bytes:");
  291         ofmt[7].type = OVER_T_INT;
  292         ofmt[7].name = my_strdup("Lines:");
  293         ofmt[8].type = OVER_T_ERROR;
  294         ofmt[8].name = NULL;
  295         fields = 8;
  296     }
  297 
  298     for (i = 0; i <= fields; i++) {
  299         if (ofmt[i].type == OVER_T_FSTRING) {
  300             if (!strcasecmp(ofmt[i].name, "Xref:"))
  301                 supported = TRUE;
  302         }
  303     }
  304 
  305     /*
  306      * If user aborted with 'q', then we continue regardless. If Xref was
  307      * found, then fair enough. If not, tough. No real harm done
  308      */
  309     /*
  310      * TODO: warning message is not correct
  311      *       - in the NNTP_ABLE but !read_news_via_nntp case when
  312      *         OVERVIEW.FMT-file wasn't found or didn't mention Xref:
  313      *       - if the used command is OVER instead of XOVER
  314      *         (use nntp_caps.over_cmd in txt_warn_xref_not_supported ?)
  315      *       - if the used command is HDR XREF instead of XHDR XREF
  316      *         (use nntp_caps.hdr_cmd in txt_warn_xref_not_supported ?)
  317      *       - if server doesn't mention XREF in LIST HEADERS
  318      */
  319     if (read_news_via_nntp && !supported)
  320         wait_message(2, _(txt_warn_xref_not_supported));
  321 
  322     return supported;
  323 }
  324 
  325 
  326 /*
  327  * mark all other Xref: crossposted articles as read when one article read
  328  * Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
  329  */
  330 void
  331 art_mark_xref_read(
  332     struct t_article *art)
  333 {
  334     char *xref_ptr;
  335     char *groupname;
  336     char *ptr, c;
  337     t_artnum artnum;
  338     struct t_group *group;
  339 #ifdef DEBUG
  340     char *debug_mesg;
  341 #endif /* DEBUG */
  342 
  343     if (art->xref == NULL)
  344         return;
  345 
  346     xref_ptr = art->xref;
  347 
  348     /*
  349      * check sitename matches nodename of current machine (ignore for now!)
  350      */
  351     while (*xref_ptr != ' ' && *xref_ptr)
  352         xref_ptr++;
  353 
  354     /*
  355      * tokenize each pair and update that newsgroup if it is in my_group[].
  356      */
  357     forever {
  358         while (*xref_ptr == ' ')
  359             xref_ptr++;
  360 
  361         groupname = xref_ptr;
  362         while (*xref_ptr != ':' && *xref_ptr)
  363             xref_ptr++;
  364 
  365         if (*xref_ptr != ':')
  366             break;
  367 
  368         ptr = xref_ptr++;
  369         artnum = atoartnum(xref_ptr);
  370         while (isdigit((int) *xref_ptr))
  371             xref_ptr++;
  372 
  373         if (&ptr[1] == xref_ptr)
  374             break;
  375 
  376         c = *ptr;
  377         *ptr = '\0';
  378         group = group_find(groupname, FALSE);
  379 
  380 #ifdef DEBUG
  381         if (debug & DEBUG_NEWSRC) {
  382             debug_mesg = fmt_string("LOOKUP Xref: [%s:%"T_ARTNUM_PFMT"] active=[%s] num_unread=[%"T_ARTNUM_PFMT"]",
  383                 groupname, artnum,
  384                 (group ? group->name : ""),
  385                 (group ? group->newsrc.num_unread : 0));
  386             debug_print_comment(debug_mesg);
  387             debug_print_bitmap(group, NULL);
  388 /*          error_message(2, debug_mesg); */
  389             free(debug_mesg);
  390         }
  391 #endif /* DEBUG */
  392 
  393         if (group && group->newsrc.xbitmap) {
  394             if (artnum >= group->newsrc.xmin && artnum <= group->xmax) {
  395                 if (!((NTEST(group->newsrc.xbitmap, artnum - group->newsrc.xmin) == ART_READ) ? TRUE : FALSE)) {
  396                     NSET0(group->newsrc.xbitmap, artnum - group->newsrc.xmin);
  397                     if (group->newsrc.num_unread > 0)
  398                         group->newsrc.num_unread--;
  399 #ifdef DEBUG
  400                     if (debug & DEBUG_NEWSRC) {
  401                         debug_mesg = fmt_string("FOUND!Xref: [%s:%"T_ARTNUM_PFMT"] marked READ num_unread=[%"T_ARTNUM_PFMT"]",
  402                             groupname, artnum, group->newsrc.num_unread);
  403                             debug_print_comment(debug_mesg);
  404                             debug_print_bitmap(group, NULL);
  405 /*                      error_message(2, debug_mesg); */
  406                         free(debug_mesg);
  407                     }
  408 #endif /* DEBUG */
  409                 }
  410             }
  411         }
  412         *ptr = c;
  413     }
  414 }
  415 
  416 
  417 /*
  418  * Set bits [low..high] of 'bitmap' to 1's
  419  */
  420 void
  421 NSETRNG1(
  422     t_bitmap *bitmap,
  423     t_artnum low,
  424     t_artnum high)
  425 {
  426     t_artnum i;
  427 
  428     if (bitmap == NULL) {
  429 #ifdef DEBUG
  430         error_message(2, "NSETRNG1() failed. Bitmap == NULL");
  431 #endif /* DEBUG */
  432         return;
  433     }
  434 
  435     if (high >= low) {
  436         if (NOFFSET(high) == NOFFSET(low)) {
  437             for (i = low; i <= high; i++) {
  438                 NSET1(bitmap, i);
  439             }
  440         } else {
  441             BIT_OR(bitmap, low, (NBITSON << NBITIDX(low)));
  442             if (NOFFSET(high) > NOFFSET(low) + 1)
  443                 memset(&bitmap[NOFFSET(low) + 1], NBITSON, (size_t) (NOFFSET(high) - NOFFSET(low) - 1));
  444 
  445             BIT_OR(bitmap, high, ~ (NBITNEG1 << NBITIDX(high)));
  446         }
  447     }
  448 }
  449 
  450 
  451 /*
  452  * Set bits [low..high] of 'bitmap' to 0's
  453  */
  454 void
  455 NSETRNG0(
  456     t_bitmap *bitmap,
  457     t_artnum low,
  458     t_artnum high)
  459 {
  460     t_artnum i;
  461 
  462     if (bitmap == NULL) {
  463         error_message(2, "NSETRNG0() failed. Bitmap == NULL");
  464         return;
  465     }
  466 
  467     if (high >= low) {
  468         if (NOFFSET(high) == NOFFSET(low)) {
  469             for (i = low; i <= high; i++) {
  470                 NSET0(bitmap, i);
  471             }
  472         } else {
  473             BIT_AND(bitmap, low, ~(NBITSON << NBITIDX(low)));
  474             if (NOFFSET(high) > NOFFSET(low) + 1)
  475                 memset(&bitmap[NOFFSET(low) + 1], 0, (size_t) (NOFFSET(high) - NOFFSET(low) - 1));
  476 
  477             BIT_AND(bitmap, high, NBITNEG1 << NBITIDX(high));
  478         }
  479     }
  480 }