tin  2.6.1
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.6.1.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

tags.c
Go to the documentation of this file.
1/*
2 * Project : tin - a Usenet reader
3 * Module : tags.c
4 * Author : Jason Faultless <jason@altarstone.com>
5 * Created : 1999-12-06
6 * Updated : 2020-08-04
7 * Notes : Split out from other modules
8 *
9 * Copyright (c) 1999-2022 Jason Faultless <jason@altarstone.com>
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#ifndef TIN_H
41# include "tin.h"
42#endif /* !TIN_H */
43
44/* Local prototypes */
45static t_bool parse_range(char *range, int min, int max, int curr, int *range_start, int *range_end);
46
48
49/*
50 * Tags all parts of a multipart index if base_index points
51 * to a multipart message and all its parts can be found.
52 *
53 * @param base_index points to one message in a multipart message.
54 * @return number of messages tagged, or zero on failure
55 */
56int
58 int arts_index)
59{
60 MultiPartInfo *info = NULL;
61 int i;
62 int qty;
63 t_bool untagging = FALSE;
64
65 for_each_art(i) {
66 if (!global_look_for_multipart(i, '[', ']'))
67 global_look_for_multipart(i, '(', ')');
68 }
69
70 qty = global_get_multiparts(arts_index, &info, TRUE);
71
72 /* check for failure... */
73 if (qty == 0) {
75 return 0;
76 }
77 if (qty < 0) {
79 return 0;
80 }
81
82 /*
83 * if any are already tagged, untag 'em
84 */
85 for (i = 0; i < qty; ++i) {
86 if (arts[info[i].arts_index].tagged != 0) {
87 untagging = TRUE;
88 while (i < qty)
89 untag_article(info[i++].arts_index);
90 }
91 }
92
93 /*
94 * get_multiparts() sorts info by part number,
95 * so a simple for loop tags in the right order
96 *
97 * only tag if we are not untagging
98 */
99 if (!untagging) {
100 for (i = 0; i < qty; ++i)
101 arts[info[i].arts_index].tagged = ++num_of_tagged_arts;
102 }
103
104 free(info);
105
106 return qty;
107}
108
109
110/*
111 * Return the highest tag number of any article in thread
112 * rooted at base[n]
113 */
114int
116 int n)
117{
118 int code = 0;
119
121 int i;
122 for (i = n; i >= 0; i = arts[i].thread) {
123 if (arts[i].tagged > code)
124 code = arts[i].tagged;
125 }
126 } else
127 code = arts[n].tagged;
128
129 return code;
130}
131
132
133/*
134 * Toggle tag status of an article. Returns TRUE if we tagged the article
135 * FALSE if we untagged it.
136 */
137t_bool
139 int art)
140{
141 if (arts[art].tagged != 0) {
144 return FALSE;
145 } else {
148 return TRUE;
149 }
150}
151
152
153/*
154 * Remove the tag from an article
155 * Work through all the threads and decrement the tag counter on all arts
156 * greater than 'tag', fixup counters
157 */
158void
160 long art)
161{
162 int i, j;
163
164 for (i = 0; i < grpmenu.max; ++i) {
166 if (arts[j].tagged > arts[art].tagged)
167 --arts[j].tagged;
168 }
169 }
170 arts[art].tagged = 0;
172}
173
174
175/*
176 * Clear tag status of all articles. If articles were untagged, return TRUE
177 */
178t_bool
180 void)
181{
182 int i;
183 t_bool untagged = FALSE;
184
185 for_each_art(i) {
186 if (arts[i].tagged != 0) {
187 arts[i].tagged = 0;
188 untagged = TRUE;
189 }
190 }
192
193 return untagged;
194}
195
196
197/*
198 * RANGE CODE
199 */
200/*
201 * Allows user to specify an group/article range that a followup
202 * command will operate on (eg. catchup articles 1-56) # 1-56 K
203 * min/max/curr are the lowest/highest and current positions on the
204 * menu from which this was called; used as defaults if needed
205 * Return TRUE if a range was successfully read, parsed and set
206 *
207 * Allowed syntax is 0123456789-.$ (blanks are ignored):
208 * 1-23 mark grp/art 1 through 23
209 * 1-. mark grp/art 1 through current
210 * 1-$ mark grp/art 1 through last
211 * .-$ mark grp/art current through last
212 */
213t_bool
215 int level,
216 int min,
217 int max,
218 int curr)
219{
220 char *range;
221 char *prompt;
222 int artnum;
223 int i;
224 int range_min;
225 int range_max;
226
227 switch (level) {
228 case SELECT_LEVEL:
230 break;
231
232 case GROUP_LEVEL:
234 break;
235
236 case THREAD_LEVEL:
238 break;
239
240 default: /* should no happen */
241 return FALSE;
242 }
243
244#if 0
245 error_message(2, "Min=[%d] Max=[%d] Cur=[%d] DefRng=[%s]", min, max, curr, range);
246#endif /* 0 */
247 prompt = fmt_string(_(txt_enter_range), range);
248
249 if (!(prompt_string_default(prompt, range, _(txt_range_invalid), HIST_OTHER))) {
250 free(prompt);
251 return FALSE;
252 }
253 free(prompt);
254
255 /*
256 * Parse range string
257 */
258 if (!parse_range(range, min, max, curr, &range_min, &range_max)) {
260 return FALSE;
261 }
262
263 switch (level) {
264 case SELECT_LEVEL:
265 for (i = 0; i < max; i++) /* Clear existing range */
266 active[my_group[i]].inrange = FALSE;
267
268 for (i = range_min - 1; i < range_max; i++)
269 active[my_group[i]].inrange = TRUE;
270 break;
271
272 case GROUP_LEVEL:
273 for (i = 0; i < max; i++) { /* Clear existing range */
274 for_each_art_in_thread(artnum, i)
275 arts[artnum].inrange = FALSE;
276 }
277
278 for (i = range_min - 1; i < range_max; i++) {
279 for_each_art_in_thread(artnum, i)
280 arts[artnum].inrange = TRUE;
281 }
282 break;
283
284 case THREAD_LEVEL:
285 /*
286 * Debatably should clear all of arts[] depending on how you
287 * interpret the (non)spec
288 */
289 for (i = 0; i < grpmenu.max; i++) { /* Clear existing range */
290 for_each_art_in_thread(artnum, i)
291 arts[artnum].inrange = FALSE;
292 }
293
294 i = 1;
296 if (i > range_max)
297 break;
298 if (i >= range_min)
299 arts[artnum].inrange = TRUE;
300 i++;
301 }
302 break;
303
304 default:
305 return FALSE;
306 /* NOTREACHED */
307 break;
308 }
309 return TRUE;
310}
311
312
313/*
314 * Parse 'range', return the range start and end values in range_start and range_end
315 * min/max/curr are used to select defaults when n explicit start/end are given
316 */
317static t_bool
319 char *range,
320 int min,
321 int max,
322 int curr,
323 int *range_start,
324 int *range_end)
325{
326 char *ptr = range;
327 enum states { FINDMIN, FINDMAX, DONE };
328 int state = FINDMIN;
329 t_bool ret = FALSE;
330
331 *range_start = -1;
332 *range_end = -1;
333
334 while (*ptr && state != DONE) {
335 if (isdigit((int) *ptr)) {
336 if (state == FINDMAX) {
337 *range_end = atoi(ptr);
338 state = DONE;
339 } else
340 *range_start = atoi(ptr);
341 while (isdigit((int) *ptr))
342 ptr++;
343 } else {
344 switch (*ptr) {
345 case '-':
346 state = FINDMAX;
347 break;
348
349 case '.':
350 if (state == FINDMAX) {
351 *range_end = curr;
352 state = DONE;
353 } else
354 *range_start = curr;
355 break;
356
357 case '$':
358 if (state == FINDMAX) {
359 *range_end = max;
360 state = DONE;
361 }
362 break;
363
364 default:
365 break;
366 }
367 ptr++;
368 }
369 }
370
371 if (*range_start >= min && *range_end >= *range_start && *range_end <= max)
372 ret = TRUE;
373
374 return ret;
375}
376
377
378/*
379 * SELECTED CODE
380 */
381void
383 void)
384{
385 int i;
386
387 for_each_art(i) {
388 if (arts[i].status == ART_UNREAD && !arts[i].selected) {
389#ifdef DEBUG
390 if (debug & DEBUG_NEWSRC)
391 debug_print_comment("group.c: X command");
392#endif /* DEBUG */
394 arts[i].zombie = TRUE;
395 }
398 }
401
402 grpmenu.curr = 0;
404}
405
406
407/* selection already happened in filter_articles() */
408void
410 void)
411{
412 int i;
413
414 for_each_art(i) {
415 if (arts[i].status == ART_READ && arts[i].zombie) {
416#ifdef DEBUG
417 if (debug & DEBUG_NEWSRC)
418 debug_print_comment("group.c: + command");
419#endif /* DEBUG */
421 arts[i].zombie = FALSE;
422 }
423 }
426
427 grpmenu.curr = 0; /* do we want this? */
429}
430
431
432void
434 void)
435{
436 int i;
437
438 for_each_art(i) {
439 arts[i].selected = FALSE;
440 arts[i].zombie = FALSE;
441 }
442}
443
444
445/*
446 * Return TRUE if there are any selected arts
447 */
448t_bool
450 void)
451{
452 int i;
453
454 for_each_art(i) {
455 if (arts[i].selected)
456 return TRUE;
457 }
458
459 return FALSE;
460}
unsigned t_bool
Definition: bool.h:77
#define TRUE
Definition: bool.h:74
#define FALSE
Definition: bool.h:70
static t_openartinfo * art
Definition: cook.c:78
#define DEBUG_NEWSRC
Definition: debug.h:50
@ HIST_OTHER
Definition: extern.h:1558
constext txt_info_missing_part[]
Definition: lang.c:553
int * my_group
Definition: memory.c:64
t_menu grpmenu
Definition: group.c:83
constext txt_enter_range[]
Definition: lang.c:180
struct t_article * arts
Definition: memory.c:69
constext txt_article_singular[]
Definition: lang.c:75
constext txt_prefix_untagged[]
Definition: lang.c:748
int thread_basenote
Definition: thread.c:51
constext txt_range_invalid[]
Definition: lang.c:769
constext txt_prefix_tagged[]
Definition: lang.c:747
struct t_group * curr_group
Definition: group.c:55
struct t_config tinrc
Definition: init.c:192
unsigned short debug
Definition: debug.c:51
constext txt_info_not_multipart_message[]
Definition: lang.c:555
struct t_group * active
Definition: memory.c:66
void find_base(struct t_group *group)
Definition: art.c:123
char * prompt_string_default(const char *prompt, char *def, const char *failtext, int history)
Definition: prompt.c:587
int atoi(const char *s)
void error_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:224
void art_mark(struct t_group *group, struct t_article *art, int flag)
Definition: newsrc.c:1611
void show_group_page(void)
Definition: group.c:961
void info_message(const char *fmt,...)
Definition: screen.c:102
int global_get_multiparts(int aindex, MultiPartInfo **malloc_and_setme_info, t_bool tagging)
Definition: art.c:1089
t_bool global_look_for_multipart(int aindex, char start, char stop)
Definition: art.c:1049
char * fmt_string(const char *fmt,...)
Definition: string.c:1386
state
Definition: save.c:56
int code
Definition: signal.c:116
t_bool zombie
Definition: tin.h:1553
int thread
Definition: tin.h:1548
t_bool inrange
Definition: tin.h:1556
t_bool keep_in_base
Definition: tin.h:1558
t_bool selected
Definition: tin.h:1555
int tagged
Definition: tin.h:1547
unsigned thread_articles
Definition: tin.h:1677
unsigned show_only_unread_arts
Definition: tin.h:1674
char default_range_thread[LEN]
Definition: tinrc.h:94
char default_range_group[LEN]
Definition: tinrc.h:92
char default_range_select[LEN]
Definition: tinrc.h:93
struct t_attribute * attribute
Definition: tin.h:1834
int curr
Definition: tin.h:2056
int max
Definition: tin.h:2057
int tag_multipart(int arts_index)
Definition: tags.c:57
t_bool tag_article(int art)
Definition: tags.c:138
t_bool set_range(int level, int min, int max, int curr)
Definition: tags.c:214
int num_of_tagged_arts
Definition: tags.c:47
void untag_article(long art)
Definition: tags.c:159
t_bool untag_all_articles(void)
Definition: tags.c:179
void do_auto_select_arts(void)
Definition: tags.c:382
t_bool arts_selected(void)
Definition: tags.c:449
int line_is_tagged(int n)
Definition: tags.c:115
static t_bool parse_range(char *range, int min, int max, int curr, int *range_start, int *range_end)
Definition: tags.c:318
void undo_auto_select_arts(void)
Definition: tags.c:409
void undo_selections(void)
Definition: tags.c:433
#define GROUP_LEVEL
Definition: tin.h:1113
#define for_each_art(x)
Definition: tin.h:2260
#define SELECT_LEVEL
Definition: tin.h:1112
#define _(Text)
Definition: tin.h:94
#define for_each_art_in_thread(x, y)
Definition: tin.h:2261
#define ART_READ
Definition: tin.h:1345
#define THREAD_LEVEL
Definition: tin.h:1114
#define ART_UNREAD
Definition: tin.h:1346