"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/src/xref.c" (9 Dec 2022, 13216 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:


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.6.1_vs_2.6.2.

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