"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 }