1 /*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * $Id: newsnntp.c,v 1.31 2011/03/11 21:49:36 hoa Exp $
34 */
35
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39
40 #include "newsnntp.h"
41
42
43 #include <stdio.h>
44 #ifndef WIN32
45 # include <unistd.h>
46 # include <netinet/in.h>
47 # include <netdb.h>
48 #endif
49
50 #include <string.h>
51 #include <stdlib.h>
52 #include <time.h>
53
54 #include "connect.h"
55 #include "mail.h"
56 #include "clist.h"
57
58 /*
59 NNTP Protocol
60
61 RFC 977
62 RFC 2980
63
64 TODO :
65
66 XPAT header range|<message-id> pat [pat...]
67
68
69 */
70
71
72
73
74 #define NNTP_STRING_SIZE 513
75
76
77 static inline void nntp_logger(mailstream * s, int log_type,
78 const char * str, size_t size, void * context);
79
80 static char * read_line(newsnntp * f);
81 static char * read_multiline(newsnntp * f, size_t size,
82 MMAPString * multiline_buffer);
83 static int parse_response(newsnntp * f, char * response);
84
85 static int send_command(newsnntp * f, char * command);
86 static int send_command_private(newsnntp * f, char * command, int can_be_published);
87
newsnntp_new(size_t progr_rate,progress_function * progr_fun)88 newsnntp * newsnntp_new(size_t progr_rate, progress_function * progr_fun)
89 {
90 newsnntp * f;
91
92 f = malloc(sizeof(* f));
93 if (f == NULL)
94 goto err;
95
96 f->nntp_stream = NULL;
97 f->nntp_readonly = FALSE;
98
99 f->nntp_progr_rate = progr_rate;
100 f->nntp_progr_fun = progr_fun;
101
102 f->nntp_stream_buffer = mmap_string_new("");
103 if (f->nntp_stream_buffer == NULL)
104 goto free_f;
105
106 f->nntp_response_buffer = mmap_string_new("");
107 if (f->nntp_response_buffer == NULL)
108 goto free_stream_buffer;
109
110 f->nntp_timeout = 0;
111 f->nntp_progress_fun = NULL;
112 f->nntp_progress_context = NULL;
113
114 f->nntp_logger = NULL;
115 f->nntp_logger_context = NULL;
116
117 return f;
118
119 free_stream_buffer:
120 mmap_string_free(f->nntp_stream_buffer);
121 free_f:
122 free(f);
123 err:
124 return NULL;
125 }
126
newsnntp_free(newsnntp * f)127 void newsnntp_free(newsnntp * f)
128 {
129 if (f->nntp_stream)
130 newsnntp_quit(f);
131
132 mmap_string_free(f->nntp_response_buffer);
133 mmap_string_free(f->nntp_stream_buffer);
134
135 free(f);
136 }
137
138
newsnntp_set_timeout(newsnntp * f,time_t timeout)139 void newsnntp_set_timeout(newsnntp * f, time_t timeout)
140 {
141 f->nntp_timeout = timeout;
142 }
143
newsnntp_get_timeout(newsnntp * f)144 time_t newsnntp_get_timeout(newsnntp * f)
145 {
146 return f->nntp_timeout;
147 }
148
149
150
151
152
newsnntp_quit(newsnntp * f)153 int newsnntp_quit(newsnntp * f)
154 {
155 char command[NNTP_STRING_SIZE];
156 char * response;
157 int r;
158 int res;
159
160 if (f->nntp_stream == NULL)
161 return NEWSNNTP_ERROR_BAD_STATE;
162
163 snprintf(command, NNTP_STRING_SIZE, "QUIT\r\n");
164 r = send_command(f, command);
165 if (r == -1) {
166 res = NEWSNNTP_ERROR_STREAM;
167 goto close;
168 }
169
170 response = read_line(f);
171 if (response == NULL) {
172 res = NEWSNNTP_ERROR_STREAM;
173 goto close;
174 }
175
176 parse_response(f, response);
177
178 res = NEWSNNTP_NO_ERROR;
179
180 close:
181
182 mailstream_close(f->nntp_stream);
183
184 f->nntp_stream = NULL;
185
186 return res;
187 }
188
newsnntp_connect(newsnntp * f,mailstream * s)189 int newsnntp_connect(newsnntp * f, mailstream * s)
190 {
191 char * response;
192 int r;
193
194 if (f->nntp_stream != NULL)
195 return NEWSNNTP_ERROR_BAD_STATE;
196
197 f->nntp_stream = s;
198 mailstream_set_logger(s, nntp_logger, f);
199
200 response = read_line(f);
201 if (response == NULL)
202 return NEWSNNTP_ERROR_STREAM;
203
204 r = parse_response(f, response);
205
206 switch (r) {
207 case 200:
208 f->nntp_readonly = FALSE;
209 return NEWSNNTP_NO_ERROR;
210
211 case 201:
212 f->nntp_readonly = TRUE;
213 return NEWSNNTP_NO_ERROR;
214
215 default:
216 f->nntp_stream = NULL;
217 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
218 }
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 /*
241 static struct newsnntp_xover_resp_item * get_xover_info(newsnntp * f,
242 guint32 article);
243 */
244
newsnntp_multiline_response_free(char * str)245 static void newsnntp_multiline_response_free(char * str)
246 {
247 mmap_string_unref(str);
248 }
249
newsnntp_head_free(char * str)250 void newsnntp_head_free(char * str)
251 {
252 newsnntp_multiline_response_free(str);
253 }
254
newsnntp_article_free(char * str)255 void newsnntp_article_free(char * str)
256 {
257 newsnntp_multiline_response_free(str);
258 }
259
newsnntp_body_free(char * str)260 void newsnntp_body_free(char * str)
261 {
262 newsnntp_multiline_response_free(str);
263 }
264
265 /* ******************** HEADER ******************************** */
266
267 /*
268 message content in (* result) is still there until the
269 next retrieve or top operation on the mailpop3 structure
270 */
271
newsnntp_get_content(newsnntp * f,char ** result,size_t * result_len)272 static int newsnntp_get_content(newsnntp * f, char ** result,
273 size_t * result_len)
274 {
275 int r;
276 char * response;
277 MMAPString * buffer;
278 char * result_multiline;
279
280 response = read_line(f);
281 if (response == NULL)
282 return NEWSNNTP_ERROR_STREAM;
283
284 r = parse_response(f, response);
285
286 switch (r) {
287 case 480:
288 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
289
290 case 381:
291 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
292
293 case 220:
294 case 221:
295 case 222:
296 case 223:
297 buffer = mmap_string_new("");
298 if (buffer == NULL)
299 return NEWSNNTP_ERROR_MEMORY;
300
301 result_multiline = read_multiline(f, 0, buffer);
302 if (result_multiline == NULL) {
303 mmap_string_free(buffer);
304 return NEWSNNTP_ERROR_MEMORY;
305 }
306 else {
307 r = mmap_string_ref(buffer);
308 if (r < 0) {
309 mmap_string_free(buffer);
310 return NEWSNNTP_ERROR_MEMORY;
311 }
312
313 * result = result_multiline;
314 * result_len = buffer->len;
315 return NEWSNNTP_NO_ERROR;
316 }
317
318 case 412:
319 return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
320
321 case 420:
322 return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
323
324 case 423:
325 return NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER;
326
327 case 430:
328 return NEWSNNTP_ERROR_ARTICLE_NOT_FOUND;
329
330 default:
331 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
332 }
333 }
334
newsnntp_head(newsnntp * f,uint32_t indx,char ** result,size_t * result_len)335 int newsnntp_head(newsnntp * f, uint32_t indx, char ** result,
336 size_t * result_len)
337 {
338 char command[NNTP_STRING_SIZE];
339 int r;
340
341 snprintf(command, NNTP_STRING_SIZE, "HEAD %i\r\n", indx);
342 r = send_command(f, command);
343 if (r == -1)
344 return NEWSNNTP_ERROR_STREAM;
345
346 return newsnntp_get_content(f, result, result_len);
347 }
348
349 /* ******************** ARTICLE ******************************** */
350
newsnntp_article(newsnntp * f,uint32_t indx,char ** result,size_t * result_len)351 int newsnntp_article(newsnntp * f, uint32_t indx, char ** result,
352 size_t * result_len)
353 {
354 char command[NNTP_STRING_SIZE];
355 int r;
356
357 snprintf(command, NNTP_STRING_SIZE, "ARTICLE %i\r\n", indx);
358 r = send_command(f, command);
359 if (r == -1)
360 return NEWSNNTP_ERROR_STREAM;
361
362 return newsnntp_get_content(f, result, result_len);
363 }
364
newsnntp_article_by_message_id(newsnntp * f,char * msg_id,char ** result,size_t * result_len)365 int newsnntp_article_by_message_id(newsnntp * f, char * msg_id,
366 char ** result, size_t * result_len)
367 {
368 char command[NNTP_STRING_SIZE];
369 int r;
370
371 snprintf(command, NNTP_STRING_SIZE, "ARTICLE <%s>\r\n", msg_id);
372 r = send_command(f, command);
373 if (r == -1)
374 return NEWSNNTP_ERROR_STREAM;
375
376 return newsnntp_get_content(f, result, result_len);
377 }
378
379 /* ******************** BODY ******************************** */
380
newsnntp_body(newsnntp * f,uint32_t indx,char ** result,size_t * result_len)381 int newsnntp_body(newsnntp * f, uint32_t indx, char ** result,
382 size_t * result_len)
383 {
384 char command[NNTP_STRING_SIZE];
385 int r;
386
387 snprintf(command, NNTP_STRING_SIZE, "BODY %i\r\n", indx);
388 r = send_command(f, command);
389 if (r == -1)
390 return NEWSNNTP_ERROR_STREAM;
391
392 return newsnntp_get_content(f, result, result_len);
393 }
394
395 /* ******************** GROUP ******************************** */
396
397 static struct newsnntp_group_info *
group_info_init(char * name,uint32_t first,uint32_t last,uint32_t count,char type)398 group_info_init(char * name, uint32_t first, uint32_t last, uint32_t count,
399 char type)
400 {
401 struct newsnntp_group_info * n;
402
403 n = malloc(sizeof(* n));
404
405 if (n == NULL)
406 return NULL;
407
408 n->grp_name = strdup(name);
409 if (n->grp_name == NULL) {
410 free(n);
411 return NULL;
412 }
413
414 n->grp_first = first;
415 n->grp_last = last;
416 n->grp_count = count;
417 n->grp_type = type;
418
419 return n;
420 }
421
group_info_free(struct newsnntp_group_info * n)422 static void group_info_free(struct newsnntp_group_info * n)
423 {
424 if (n->grp_name)
425 free(n->grp_name);
426 free(n);
427 }
428
group_info_list_free(clist * l)429 static void group_info_list_free(clist * l)
430 {
431 clist_foreach(l, (clist_func) group_info_free, NULL);
432 clist_free(l);
433 }
434
435 static int parse_group_info(char * response,
436 struct newsnntp_group_info ** info);
437
newsnntp_group(newsnntp * f,const char * groupname,struct newsnntp_group_info ** info)438 int newsnntp_group(newsnntp * f, const char * groupname,
439 struct newsnntp_group_info ** info)
440 {
441 char command[NNTP_STRING_SIZE];
442 int r;
443 char * response;
444
445 snprintf(command, NNTP_STRING_SIZE, "GROUP %s\r\n", groupname);
446 r = send_command(f, command);
447 if (r == -1)
448 return NEWSNNTP_ERROR_STREAM;
449
450 response = read_line(f);
451 if (response == NULL)
452 return NEWSNNTP_ERROR_STREAM;
453
454 r = parse_response(f, response);
455
456 switch (r) {
457 case 480:
458 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
459
460 case 381:
461 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
462
463 case 211:
464 if (!parse_group_info(f->nntp_response, info))
465 return NEWSNNTP_ERROR_INVALID_RESPONSE;
466 return NEWSNNTP_NO_ERROR;
467
468 case 411:
469 return NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP;
470
471 default:
472 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
473 }
474 }
475
newsnntp_group_free(struct newsnntp_group_info * info)476 void newsnntp_group_free(struct newsnntp_group_info * info)
477 {
478 group_info_free(info);
479 }
480
481 /* ******************** LIST ******************************** */
482
483 static clist * read_groups_list(newsnntp * f);
484
newsnntp_list(newsnntp * f,clist ** result)485 int newsnntp_list(newsnntp * f, clist ** result)
486 {
487 char command[NNTP_STRING_SIZE];
488 int r;
489 char * response;
490
491 snprintf(command, NNTP_STRING_SIZE, "LIST\r\n");
492 r = send_command(f, command);
493 if (r == -1)
494 return NEWSNNTP_ERROR_STREAM;
495
496 response = read_line(f);
497 if (response == NULL)
498 return NEWSNNTP_ERROR_STREAM;
499
500 r = parse_response(f, response);
501
502 switch (r) {
503 case 480:
504 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
505
506 case 381:
507 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
508
509 case 215:
510 * result = read_groups_list(f);
511 return NEWSNNTP_NO_ERROR;
512
513 default:
514 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
515 }
516 }
517
newsnntp_list_free(clist * l)518 void newsnntp_list_free(clist * l)
519 {
520 group_info_list_free(l);
521 }
522
523 /* ******************** POST ******************************** */
524
send_data(newsnntp * f,const char * message,size_t size)525 static void send_data(newsnntp * f, const char * message, size_t size)
526 {
527 mailstream_send_data(f->nntp_stream, message, size,
528 f->nntp_progr_rate, f->nntp_progr_fun);
529 }
530
531
newsnntp_post(newsnntp * f,const char * message,size_t size)532 int newsnntp_post(newsnntp * f, const char * message, size_t size)
533 {
534 char command[NNTP_STRING_SIZE];
535 int r;
536 char * response;
537
538 snprintf(command, NNTP_STRING_SIZE, "POST\r\n");
539 r = send_command(f, command);
540 if (r == -1)
541 return NEWSNNTP_ERROR_STREAM;
542
543 response = read_line(f);
544 if (response == NULL)
545 return NEWSNNTP_ERROR_STREAM;
546
547 r = parse_response(f, response);
548
549 switch (r) {
550 case 480:
551 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
552
553 case 381:
554 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
555
556 case 340:
557 break;
558
559 case 440:
560 return NEWSNNTP_ERROR_POSTING_NOT_ALLOWED;
561
562 default:
563 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
564 }
565
566 send_data(f, message, size);
567
568 response = read_line(f);
569 if (response == NULL)
570 return NEWSNNTP_ERROR_STREAM;
571
572 r = parse_response(f, response);
573
574 switch (r) {
575 case 480:
576 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
577
578 case 381:
579 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
580
581 case 240:
582 return NEWSNNTP_NO_ERROR;
583 return 1;
584
585 case 441:
586 return NEWSNNTP_ERROR_POSTING_FAILED;
587
588 default:
589 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
590 }
591 }
592
593
594 /* ******************** AUTHINFO ******************************** */
595
newsnntp_authinfo_username(newsnntp * f,const char * username)596 int newsnntp_authinfo_username(newsnntp * f, const char * username)
597 {
598 char command[NNTP_STRING_SIZE];
599 int r;
600 char * response;
601
602 snprintf(command, NNTP_STRING_SIZE, "AUTHINFO USER %s\r\n", username);
603 r = send_command_private(f, command, 0);
604 if (r == -1)
605 return NEWSNNTP_ERROR_STREAM;
606
607 response = read_line(f);
608 if (response == NULL)
609 return NEWSNNTP_ERROR_STREAM;
610
611 r = parse_response(f, response);
612
613 switch (r) {
614 case 480:
615 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
616
617 case 481:
618 return NEWSNNTP_ERROR_AUTHENTICATION_REJECTED;
619
620 case 482:
621 return NEWSNNTP_ERROR_AUTHENTICATION_OUT_OF_SEQUENCE;
622
623 case 381:
624 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
625
626 case 281:
627 return NEWSNNTP_NO_ERROR;
628
629 default:
630 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
631 }
632 }
633
newsnntp_authinfo_password(newsnntp * f,const char * password)634 int newsnntp_authinfo_password(newsnntp * f, const char * password)
635 {
636 char command[NNTP_STRING_SIZE];
637 int r;
638 char * response;
639
640 snprintf(command, NNTP_STRING_SIZE, "AUTHINFO PASS %s\r\n", password);
641 r = send_command_private(f, command, 0);
642 if (r == -1)
643 return NEWSNNTP_ERROR_STREAM;
644
645 response = read_line(f);
646 if (response == NULL)
647 return NEWSNNTP_ERROR_STREAM;
648
649 r = parse_response(f, response);
650
651 switch (r) {
652 case 480:
653 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
654
655 case 481:
656 return NEWSNNTP_ERROR_AUTHENTICATION_REJECTED;
657
658 case 482:
659 return NEWSNNTP_ERROR_AUTHENTICATION_OUT_OF_SEQUENCE;
660
661 case 381:
662 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
663
664 case 281:
665 return NEWSNNTP_NO_ERROR;
666
667 default:
668 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
669 }
670 }
671
672 /* ******************** LIST OVERVIEW.FMT ******************************** */
673
674 static clist * read_headers_list(newsnntp * f);
675
headers_list_free(clist * l)676 static void headers_list_free(clist * l)
677 {
678 clist_foreach(l, (clist_func) free, NULL);
679 clist_free(l);
680 }
681
newsnntp_list_overview_fmt(newsnntp * f,clist ** result)682 int newsnntp_list_overview_fmt(newsnntp * f, clist ** result)
683 {
684 char command[NNTP_STRING_SIZE];
685 int r;
686 char * response;
687
688 snprintf(command, NNTP_STRING_SIZE, "LIST OVERVIEW.FMT\r\n");
689 r = send_command(f, command);
690 if (r == -1)
691 return NEWSNNTP_ERROR_STREAM;
692
693 response = read_line(f);
694 if (response == NULL)
695 return NEWSNNTP_ERROR_STREAM;
696
697 r = parse_response(f, response);
698
699 switch (r) {
700 case 480:
701 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
702
703 case 381:
704 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
705
706 case 215:
707 * result = read_headers_list(f);
708 return NEWSNNTP_NO_ERROR;
709
710 case 503:
711 return NEWSNNTP_ERROR_PROGRAM_ERROR;
712
713 default:
714 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
715 }
716 }
717
newsnntp_list_overview_fmt_free(clist * l)718 void newsnntp_list_overview_fmt_free(clist * l)
719 {
720 headers_list_free(l);
721 }
722
723
724
725
726
727
728 /* ******************** LIST ACTIVE ******************************** */
729
newsnntp_list_active(newsnntp * f,const char * wildcard,clist ** result)730 int newsnntp_list_active(newsnntp * f, const char * wildcard, clist ** result)
731 {
732 char command[NNTP_STRING_SIZE];
733 int r;
734 char * response;
735
736 if (wildcard != NULL)
737 snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE %s\r\n", wildcard);
738 else
739 snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE\r\n");
740 r = send_command(f, command);
741 if (r == -1)
742 return NEWSNNTP_ERROR_STREAM;
743
744 response = read_line(f);
745 if (response == NULL)
746 return NEWSNNTP_ERROR_STREAM;
747
748 r = parse_response(f, response);
749
750 switch (r) {
751 case 480:
752 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
753
754 case 381:
755 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
756
757 case 215:
758 * result = read_groups_list(f);
759 return NEWSNNTP_NO_ERROR;
760
761 default:
762 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
763 }
764 }
765
newsnntp_list_active_free(clist * l)766 void newsnntp_list_active_free(clist * l)
767 {
768 group_info_list_free(l);
769 }
770
771
772
773
774
775
776 /* ******************** LIST ACTIVE.TIMES ******************************** */
777
778 static struct newsnntp_group_time *
group_time_new(char * group_name,time_t date,char * email)779 group_time_new(char * group_name, time_t date, char * email)
780 {
781 struct newsnntp_group_time * n;
782
783 n = malloc(sizeof(* n));
784
785 if (n == NULL)
786 return NULL;
787
788 n->grp_name = strdup(group_name);
789 if (n->grp_name == NULL) {
790 free(n);
791 return NULL;
792 }
793
794 n->grp_email = strdup(email);
795 if (n->grp_email == NULL) {
796 free(n->grp_name);
797 free(n);
798 return NULL;
799 }
800
801 n->grp_date = date;
802
803 return n;
804 }
805
group_time_free(struct newsnntp_group_time * n)806 static void group_time_free(struct newsnntp_group_time * n)
807 {
808 if (n->grp_name)
809 free(n->grp_name);
810 if (n->grp_email)
811 free(n->grp_email);
812 free(n);
813 }
814
group_time_list_free(clist * l)815 static void group_time_list_free(clist * l)
816 {
817 clist_foreach(l, (clist_func) group_time_free, NULL);
818 clist_free(l);
819 }
820
821
822
823
824
825
826
827 static clist * read_group_time_list(newsnntp * f);
828
829
newsnntp_list_active_times(newsnntp * f,clist ** result)830 int newsnntp_list_active_times(newsnntp * f, clist ** result)
831 {
832 char command[NNTP_STRING_SIZE];
833 int r;
834 char * response;
835
836 snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE.TIMES\r\n");
837 r = send_command(f, command);
838 if (r == -1)
839 return NEWSNNTP_ERROR_STREAM;
840
841 response = read_line(f);
842 if (response == NULL)
843 return NEWSNNTP_ERROR_STREAM;
844
845 r = parse_response(f, response);
846
847 switch (r) {
848 case 480:
849 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
850
851 case 381:
852 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
853
854 case 215:
855 * result = read_group_time_list(f);
856 return NEWSNNTP_NO_ERROR;
857
858 case 503:
859 return NEWSNNTP_ERROR_PROGRAM_ERROR;
860
861 default:
862 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
863 }
864 }
865
newsnntp_list_active_times_free(clist * l)866 void newsnntp_list_active_times_free(clist * l)
867 {
868 group_time_list_free(l);
869 }
870
871
872
873
874
875
876
877
878 /* ********************** LIST DISTRIBUTION ***************************** */
879
880 static struct newsnntp_distrib_value_meaning *
distrib_value_meaning_new(char * value,char * meaning)881 distrib_value_meaning_new(char * value, char * meaning)
882 {
883 struct newsnntp_distrib_value_meaning * n;
884
885 n = malloc(sizeof(* n));
886
887 if (n == NULL)
888 return NULL;
889
890 n->dst_value = strdup(value);
891 if (n->dst_value == NULL) {
892 free(n);
893 return NULL;
894 }
895
896 n->dst_meaning = strdup(meaning);
897 if (n->dst_meaning == NULL) {
898 free(n->dst_value);
899 free(n);
900 return NULL;
901 }
902
903 return n;
904 }
905
906
907 static void
distrib_value_meaning_free(struct newsnntp_distrib_value_meaning * n)908 distrib_value_meaning_free(struct newsnntp_distrib_value_meaning * n)
909 {
910 if (n->dst_value)
911 free(n->dst_value);
912 if (n->dst_meaning)
913 free(n->dst_meaning);
914 free(n);
915 }
916
distrib_value_meaning_list_free(clist * l)917 static void distrib_value_meaning_list_free(clist * l)
918 {
919 clist_foreach(l, (clist_func) distrib_value_meaning_free, NULL);
920 clist_free(l);
921 }
922
923 static clist * read_distrib_value_meaning_list(newsnntp * f);
924
925
newsnntp_list_distribution(newsnntp * f,clist ** result)926 int newsnntp_list_distribution(newsnntp * f, clist ** result)
927 {
928 char command[NNTP_STRING_SIZE];
929 int r;
930 char * response;
931
932 snprintf(command, NNTP_STRING_SIZE, "LIST DISTRIBUTIONS\r\n");
933 r = send_command(f, command);
934 if (r == -1)
935 return NEWSNNTP_ERROR_STREAM;
936
937 response = read_line(f);
938 if (response == NULL)
939 return NEWSNNTP_ERROR_STREAM;
940
941 r = parse_response(f, response);
942
943 switch (r) {
944 case 480:
945 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
946
947 case 381:
948 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
949
950 case 215:
951 * result = read_distrib_value_meaning_list(f);
952 return NEWSNNTP_NO_ERROR;
953
954 case 503:
955 return NEWSNNTP_ERROR_PROGRAM_ERROR;
956
957 default:
958 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
959 }
960 }
961
962
newsnntp_list_distribution_free(clist * l)963 void newsnntp_list_distribution_free(clist * l)
964 {
965 distrib_value_meaning_list_free(l);
966 }
967
968
969
970
971
972
973
974
975
976
977
978 /* ********************** LIST DISTRIB.PATS ***************************** */
979
980 static struct newsnntp_distrib_default_value *
distrib_default_value_new(uint32_t weight,char * group_pattern,char * value)981 distrib_default_value_new(uint32_t weight, char * group_pattern, char * value)
982 {
983 struct newsnntp_distrib_default_value * n;
984
985 n = malloc(sizeof(* n));
986 if (n == NULL)
987 return NULL;
988
989 n->dst_group_pattern = strdup(group_pattern);
990 if (n->dst_group_pattern == NULL) {
991 free(n);
992 return NULL;
993 }
994
995 n->dst_value = strdup(value);
996 if (n->dst_value == NULL) {
997 free(n->dst_group_pattern);
998 free(n);
999 return NULL;
1000 }
1001
1002 n->dst_weight = weight;
1003
1004 return n;
1005 }
1006
1007 static void
distrib_default_value_free(struct newsnntp_distrib_default_value * n)1008 distrib_default_value_free(struct newsnntp_distrib_default_value * n)
1009 {
1010 if (n->dst_group_pattern)
1011 free(n->dst_group_pattern);
1012 if (n->dst_value)
1013 free(n->dst_value);
1014 free(n);
1015 }
1016
distrib_default_value_list_free(clist * l)1017 static void distrib_default_value_list_free(clist * l)
1018 {
1019 clist_foreach(l, (clist_func) distrib_default_value_free, NULL);
1020 clist_free(l);
1021 }
1022
1023 static clist * read_distrib_default_value_list(newsnntp * f);
1024
newsnntp_list_distrib_pats(newsnntp * f,clist ** result)1025 int newsnntp_list_distrib_pats(newsnntp * f, clist ** result)
1026 {
1027 char command[NNTP_STRING_SIZE];
1028 int r;
1029 char * response;
1030
1031 snprintf(command, NNTP_STRING_SIZE, "LIST DISTRIB.PATS\r\n");
1032 r = send_command(f, command);
1033 if (r == -1)
1034 return NEWSNNTP_ERROR_STREAM;
1035
1036 response = read_line(f);
1037 if (response == NULL)
1038 return NEWSNNTP_ERROR_STREAM;
1039
1040 r = parse_response(f, response);
1041
1042 switch (r) {
1043 case 480:
1044 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1045
1046 case 381:
1047 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1048
1049 case 215:
1050 * result = read_distrib_default_value_list(f);
1051 return NEWSNNTP_NO_ERROR;
1052
1053 case 503:
1054 return NEWSNNTP_ERROR_PROGRAM_ERROR;
1055
1056 default:
1057 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1058 }
1059 }
1060
newsnntp_list_distrib_pats_free(clist * l)1061 void newsnntp_list_distrib_pats_free(clist * l)
1062 {
1063 distrib_default_value_list_free(l);
1064 }
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077 /* ********************** LIST NEWSGROUPS ***************************** */
1078
1079 static struct newsnntp_group_description *
group_description_new(char * group_name,char * description)1080 group_description_new(char * group_name, char * description)
1081 {
1082 struct newsnntp_group_description * n;
1083
1084 n = malloc(sizeof(* n));
1085 if (n == NULL)
1086 return NULL;
1087
1088 n->grp_name = strdup(group_name);
1089 if (n->grp_name == NULL) {
1090 free(n);
1091 return NULL;
1092 }
1093
1094 n->grp_description = strdup(description);
1095 if (n->grp_description == NULL) {
1096 free(n->grp_name);
1097 free(n);
1098 return NULL;
1099 }
1100
1101 return n;
1102 }
1103
group_description_free(struct newsnntp_group_description * n)1104 static void group_description_free(struct newsnntp_group_description * n)
1105 {
1106 if (n->grp_name)
1107 free(n->grp_name);
1108 if (n->grp_description)
1109 free(n->grp_description);
1110 free(n);
1111 }
1112
group_description_list_free(clist * l)1113 static void group_description_list_free(clist * l)
1114 {
1115 clist_foreach(l, (clist_func) group_description_free, NULL);
1116 clist_free(l);
1117 }
1118
1119 static clist * read_group_description_list(newsnntp * f);
1120
newsnntp_list_newsgroups(newsnntp * f,const char * pattern,clist ** result)1121 int newsnntp_list_newsgroups(newsnntp * f, const char * pattern,
1122 clist ** result)
1123 {
1124 char command[NNTP_STRING_SIZE];
1125 int r;
1126 char * response;
1127
1128 if (pattern)
1129 snprintf(command, NNTP_STRING_SIZE, "LIST NEWSGROUPS %s\r\n", pattern);
1130 else
1131 snprintf(command, NNTP_STRING_SIZE, "LIST NEWSGROUPS\r\n");
1132
1133 r = send_command(f, command);
1134 if (r == -1)
1135 return NEWSNNTP_ERROR_STREAM;
1136
1137 response = read_line(f);
1138 if (response == NULL)
1139 return NEWSNNTP_ERROR_STREAM;
1140
1141 r = parse_response(f, response);
1142
1143 switch (r) {
1144 case 480:
1145 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1146
1147 case 381:
1148 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1149
1150 case 215:
1151 * result = read_group_description_list(f);
1152 return NEWSNNTP_NO_ERROR;
1153
1154 case 503:
1155 return NEWSNNTP_ERROR_PROGRAM_ERROR;
1156
1157 default:
1158 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1159 }
1160 }
1161
newsnntp_list_newsgroups_free(clist * l)1162 void newsnntp_list_newsgroups_free(clist * l)
1163 {
1164 group_description_list_free(l);
1165 }
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178 /* ******************** LIST SUBSCRIPTIONS ******************************** */
1179
subscriptions_list_free(clist * l)1180 static void subscriptions_list_free(clist * l)
1181 {
1182 clist_foreach(l, (clist_func) free, NULL);
1183 clist_free(l);
1184 }
1185
1186 static clist * read_subscriptions_list(newsnntp * f);
1187
newsnntp_list_subscriptions(newsnntp * f,clist ** result)1188 int newsnntp_list_subscriptions(newsnntp * f, clist ** result)
1189 {
1190 char command[NNTP_STRING_SIZE];
1191 int r;
1192 char * response;
1193
1194 snprintf(command, NNTP_STRING_SIZE, "LIST SUBSCRIPTIONS\r\n");
1195 r = send_command(f, command);
1196 if (r == -1)
1197 return NEWSNNTP_ERROR_STREAM;
1198
1199 response = read_line(f);
1200 if (response == NULL)
1201 return NEWSNNTP_ERROR_STREAM;
1202
1203 r = parse_response(f, response);
1204
1205 switch (r) {
1206 case 480:
1207 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1208
1209 case 381:
1210 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1211
1212 case 215:
1213 * result = read_subscriptions_list(f);
1214 return NEWSNNTP_NO_ERROR;
1215
1216 case 503:
1217 return NEWSNNTP_ERROR_PROGRAM_ERROR;
1218
1219 default:
1220 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1221 }
1222 }
1223
newsnntp_list_subscriptions_free(clist * l)1224 void newsnntp_list_subscriptions_free(clist * l)
1225 {
1226 subscriptions_list_free(l);
1227 }
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240 /* ******************** LISTGROUP ******************************** */
1241
articles_list_free(clist * l)1242 static void articles_list_free(clist * l)
1243 {
1244 clist_foreach(l, (clist_func) free, NULL);
1245 clist_free(l);
1246 }
1247
1248 static clist * read_articles_list(newsnntp * f);
1249
newsnntp_listgroup(newsnntp * f,const char * group_name,clist ** result)1250 int newsnntp_listgroup(newsnntp * f, const char * group_name,
1251 clist ** result)
1252 {
1253 char command[NNTP_STRING_SIZE];
1254 int r;
1255 char * response;
1256
1257 if (group_name)
1258 snprintf(command, NNTP_STRING_SIZE, "LISTGROUP %s\r\n", group_name);
1259 else
1260 snprintf(command, NNTP_STRING_SIZE, "LISTGROUP\r\n");
1261 r = send_command(f, command);
1262 if (r == -1)
1263 return NEWSNNTP_ERROR_STREAM;
1264
1265 response = read_line(f);
1266 if (response == NULL)
1267 return NEWSNNTP_ERROR_STREAM;
1268
1269 r = parse_response(f, response);
1270
1271 switch (r) {
1272 case 480:
1273 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1274
1275 case 381:
1276 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1277
1278 case 211:
1279 * result = read_articles_list(f);
1280 return NEWSNNTP_NO_ERROR;
1281
1282 case 412:
1283 return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
1284
1285 case 502:
1286 return NEWSNNTP_ERROR_NO_PERMISSION;
1287
1288 default:
1289 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1290 }
1291 }
1292
newsnntp_listgroup_free(clist * l)1293 void newsnntp_listgroup_free(clist * l)
1294 {
1295 articles_list_free(l);
1296 }
1297
1298
1299
1300
1301
1302
1303
1304 /* ********************** MODE READER ***************************** */
1305
newsnntp_mode_reader(newsnntp * f)1306 int newsnntp_mode_reader(newsnntp * f)
1307 {
1308 char command[NNTP_STRING_SIZE];
1309 char * response;
1310 int r;
1311
1312 snprintf(command, NNTP_STRING_SIZE, "MODE READER\r\n");
1313
1314 r = send_command(f, command);
1315 if (r == -1)
1316 return NEWSNNTP_ERROR_STREAM;
1317
1318 response = read_line(f);
1319 if (response == NULL)
1320 return NEWSNNTP_ERROR_STREAM;
1321
1322 r = parse_response(f, response);
1323 switch (r) {
1324 case 480:
1325 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1326
1327 case 381:
1328 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1329
1330 case 200:
1331 case 201:
1332 return NEWSNNTP_NO_ERROR;
1333
1334 default:
1335 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1336 }
1337 }
1338
1339 /* ********************** DATE ***************************** */
1340
1341 #define strfcpy(a,b,c) {if (c) {strncpy(a,b,c);a[c-1]=0;}}
1342
newsnntp_date(newsnntp * f,struct tm * tm)1343 int newsnntp_date(newsnntp * f, struct tm * tm)
1344 {
1345 char command[NNTP_STRING_SIZE];
1346 int r;
1347 char * response;
1348 char year[5];
1349 char month[3];
1350 char day[3];
1351 char hour[3];
1352 char minute[3];
1353 char second[3];
1354
1355 snprintf(command, NNTP_STRING_SIZE, "DATE\r\n");
1356 r = send_command(f, command);
1357 if (r == -1)
1358 return NEWSNNTP_ERROR_STREAM;
1359
1360 response = read_line(f);
1361 if (response == NULL)
1362 return NEWSNNTP_ERROR_STREAM;
1363
1364 r = parse_response(f, response);
1365 if (f->nntp_response == NULL) {
1366 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1367 }
1368
1369 switch (r) {
1370 case 111:
1371 strfcpy(year, f->nntp_response, 4);
1372 strfcpy(month, f->nntp_response + 4, 2);
1373 strfcpy(day, f->nntp_response + 6, 2);
1374 strfcpy(hour, f->nntp_response + 8, 2);
1375 strfcpy(minute, f->nntp_response + 10, 2);
1376 strfcpy(second, f->nntp_response + 12, 2);
1377
1378 tm->tm_year = atoi(year);
1379 tm->tm_mon = atoi(month);
1380 tm->tm_mday = atoi(day);
1381 tm->tm_hour = atoi(hour);
1382 tm->tm_min = atoi(minute);
1383 tm->tm_sec = atoi(second);
1384
1385 return NEWSNNTP_NO_ERROR;
1386
1387 default:
1388 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1389 }
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 /* ********************** XHDR ***************************** */
1401
xhdr_resp_item_new(uint32_t article,char * value)1402 static struct newsnntp_xhdr_resp_item * xhdr_resp_item_new(uint32_t article,
1403 char * value)
1404 {
1405 struct newsnntp_xhdr_resp_item * n;
1406
1407 n = malloc(sizeof(* n));
1408 if (n == NULL)
1409 return NULL;
1410
1411 n->hdr_value = strdup(value);
1412 if (n->hdr_value == NULL) {
1413 free(n);
1414 return NULL;
1415 }
1416
1417 n->hdr_article = article;
1418
1419 return n;
1420 }
1421
xhdr_resp_item_free(struct newsnntp_xhdr_resp_item * n)1422 static void xhdr_resp_item_free(struct newsnntp_xhdr_resp_item * n)
1423 {
1424 if (n->hdr_value)
1425 free(n->hdr_value);
1426 free(n);
1427 }
1428
xhdr_resp_list_free(clist * l)1429 static void xhdr_resp_list_free(clist * l)
1430 {
1431 clist_foreach(l, (clist_func) xhdr_resp_item_free, NULL);
1432 clist_free(l);
1433 }
1434
1435 static clist * read_xhdr_resp_list(newsnntp * f);
1436
1437 static int newsnntp_xhdr_resp(newsnntp * f, clist ** result);
1438
newsnntp_xhdr_single(newsnntp * f,const char * header,uint32_t article,clist ** result)1439 int newsnntp_xhdr_single(newsnntp * f, const char * header, uint32_t article,
1440 clist ** result)
1441 {
1442 char command[NNTP_STRING_SIZE];
1443 int r;
1444
1445 snprintf(command, NNTP_STRING_SIZE, "XHDR %s %i\r\n", header, article);
1446 r = send_command(f, command);
1447 if (r == -1)
1448 return NEWSNNTP_ERROR_STREAM;
1449
1450 return newsnntp_xhdr_resp(f, result);
1451 }
1452
newsnntp_xhdr_range(newsnntp * f,const char * header,uint32_t rangeinf,uint32_t rangesup,clist ** result)1453 int newsnntp_xhdr_range(newsnntp * f, const char * header,
1454 uint32_t rangeinf, uint32_t rangesup,
1455 clist ** result)
1456 {
1457 char command[NNTP_STRING_SIZE];
1458 int r;
1459
1460 snprintf(command, NNTP_STRING_SIZE, "XHDR %s %i-%i\r\n", header,
1461 rangeinf, rangesup);
1462 r = send_command(f, command);
1463 if (r == -1)
1464 return NEWSNNTP_ERROR_STREAM;
1465
1466 return newsnntp_xhdr_resp(f, result);
1467 }
1468
newsnntp_xhdr_free(clist * l)1469 void newsnntp_xhdr_free(clist * l)
1470 {
1471 xhdr_resp_list_free(l);
1472 }
1473
newsnntp_xhdr_resp(newsnntp * f,clist ** result)1474 static int newsnntp_xhdr_resp(newsnntp * f, clist ** result)
1475 {
1476 int r;
1477 char * response;
1478
1479 response = read_line(f);
1480 if (response == NULL)
1481 return NEWSNNTP_ERROR_STREAM;
1482
1483 r = parse_response(f, response);
1484
1485 switch (r) {
1486 case 480:
1487 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1488
1489 case 381:
1490 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1491
1492 case 221:
1493 * result = read_xhdr_resp_list(f);
1494 return NEWSNNTP_NO_ERROR;
1495
1496 case 412:
1497 return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
1498
1499 case 420:
1500 return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
1501
1502 case 430:
1503 return NEWSNNTP_ERROR_ARTICLE_NOT_FOUND;
1504
1505 case 502:
1506 return NEWSNNTP_ERROR_NO_PERMISSION;
1507
1508 default:
1509 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1510 }
1511 }
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526 /* ********************** XOVER ***************************** */
1527
1528 static struct newsnntp_xover_resp_item *
xover_resp_item_new(uint32_t article,char * subject,char * author,char * date,char * message_id,char * references,size_t size,uint32_t line_count,clist * others)1529 xover_resp_item_new(uint32_t article,
1530 char * subject,
1531 char * author,
1532 char * date,
1533 char * message_id,
1534 char * references,
1535 size_t size,
1536 uint32_t line_count,
1537 clist * others)
1538 {
1539 struct newsnntp_xover_resp_item * n;
1540
1541 n = malloc(sizeof(* n));
1542 if (n == NULL)
1543 return NULL;
1544
1545 n->ovr_subject = strdup(subject);
1546 if (n->ovr_subject == NULL) {
1547 free(n);
1548 return NULL;
1549 }
1550
1551 n->ovr_author = strdup(author);
1552 if (n->ovr_author == NULL) {
1553 free(n->ovr_subject);
1554 free(n);
1555 return NULL;
1556 }
1557
1558 n->ovr_date = strdup(date);
1559 if (n->ovr_date == NULL) {
1560 free(n->ovr_subject);
1561 free(n->ovr_author);
1562 free(n);
1563 return NULL;
1564 }
1565
1566 n->ovr_message_id = strdup(message_id);
1567 if (n->ovr_message_id == NULL) {
1568 free(n->ovr_subject);
1569 free(n->ovr_author);
1570 free(n->ovr_date);
1571 free(n);
1572 return NULL;
1573 }
1574
1575 n->ovr_references = strdup(references);
1576 if (n->ovr_references == NULL) {
1577 free(n->ovr_subject);
1578 free(n->ovr_author);
1579 free(n->ovr_date);
1580 free(n->ovr_message_id);
1581 free(n);
1582 return NULL;
1583 }
1584
1585 n->ovr_article = article;
1586 n->ovr_size = size;
1587 n->ovr_line_count = line_count;
1588 n->ovr_others = others;
1589
1590 return n;
1591 }
1592
xover_resp_item_free(struct newsnntp_xover_resp_item * n)1593 void xover_resp_item_free(struct newsnntp_xover_resp_item * n)
1594 {
1595 if (n->ovr_subject)
1596 free(n->ovr_subject);
1597 if (n->ovr_author)
1598 free(n->ovr_author);
1599 if (n->ovr_date)
1600 free(n->ovr_date);
1601 if (n->ovr_message_id)
1602 free(n->ovr_message_id);
1603 if (n->ovr_references)
1604 free(n->ovr_references);
1605 clist_foreach(n->ovr_others, (clist_func) free, NULL);
1606 clist_free(n->ovr_others);
1607
1608 free(n);
1609 }
1610
newsnntp_xover_resp_list_free(clist * l)1611 void newsnntp_xover_resp_list_free(clist * l)
1612 {
1613 clist_foreach(l, (clist_func) xover_resp_item_free, NULL);
1614 clist_free(l);
1615 }
1616
1617 static clist * read_xover_resp_list(newsnntp * f);
1618
1619
1620 static int newsnntp_xover_resp(newsnntp * f, clist ** result);
1621
newsnntp_xover_single(newsnntp * f,uint32_t article,struct newsnntp_xover_resp_item ** result)1622 int newsnntp_xover_single(newsnntp * f, uint32_t article,
1623 struct newsnntp_xover_resp_item ** result)
1624 {
1625 char command[NNTP_STRING_SIZE];
1626 int r;
1627 clist * list;
1628 clistiter * cur;
1629 struct newsnntp_xover_resp_item * item;
1630
1631 snprintf(command, NNTP_STRING_SIZE, "XOVER %i\r\n", article);
1632 r = send_command(f, command);
1633 if (r == -1)
1634 return NEWSNNTP_ERROR_STREAM;
1635
1636 r = newsnntp_xover_resp(f, &list);
1637 if (r != NEWSNNTP_NO_ERROR)
1638 return r;
1639
1640 cur = clist_begin(list);
1641 item = clist_content(cur);
1642 clist_free(list);
1643
1644 * result = item;
1645
1646 return r;
1647 }
1648
newsnntp_xover_range(newsnntp * f,uint32_t rangeinf,uint32_t rangesup,clist ** result)1649 int newsnntp_xover_range(newsnntp * f, uint32_t rangeinf, uint32_t rangesup,
1650 clist ** result)
1651 {
1652 int r;
1653 char command[NNTP_STRING_SIZE];
1654
1655 snprintf(command, NNTP_STRING_SIZE, "XOVER %i-%i\r\n", rangeinf, rangesup);
1656 r = send_command(f, command);
1657 if (r == -1)
1658 return NEWSNNTP_ERROR_STREAM;
1659
1660 return newsnntp_xover_resp(f, result);
1661 }
1662
newsnntp_xover_resp(newsnntp * f,clist ** result)1663 static int newsnntp_xover_resp(newsnntp * f, clist ** result)
1664 {
1665 int r;
1666 char * response;
1667
1668 response = read_line(f);
1669 if (response == NULL)
1670 return NEWSNNTP_ERROR_STREAM;
1671
1672 r = parse_response(f, response);
1673
1674 switch (r) {
1675 case 480:
1676 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1677
1678 case 381:
1679 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1680
1681 case 224:
1682 * result = read_xover_resp_list(f);
1683 return NEWSNNTP_NO_ERROR;
1684
1685 case 412:
1686 return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
1687
1688 case 420:
1689 return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
1690
1691 case 502:
1692 return NEWSNNTP_ERROR_NO_PERMISSION;
1693
1694 default:
1695 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1696 }
1697 }
1698
1699
1700
1701
1702
1703
1704
1705 /* ********************** AUTHINFO GENERIC ***************************** */
1706
newsnntp_authinfo_generic(newsnntp * f,const char * authentificator,const char * arguments)1707 int newsnntp_authinfo_generic(newsnntp * f, const char * authentificator,
1708 const char * arguments)
1709 {
1710 char command[NNTP_STRING_SIZE];
1711 int r;
1712 char * response;
1713
1714 snprintf(command, NNTP_STRING_SIZE, "AUTHINFO GENERIC %s %s\r\n",
1715 authentificator, arguments);
1716 r = send_command(f, command);
1717 if (r == -1)
1718 return NEWSNNTP_ERROR_STREAM;
1719
1720 response = read_line(f);
1721 if (response == NULL)
1722 return NEWSNNTP_ERROR_STREAM;
1723
1724 r = parse_response(f, response);
1725
1726 switch (r) {
1727 case 480:
1728 return NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME;
1729
1730 case 381:
1731 return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
1732
1733 case 281:
1734 return NEWSNNTP_NO_ERROR;
1735
1736 case 500:
1737 return NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD;
1738
1739 case 501:
1740 return NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED;
1741
1742 case 502:
1743 return NEWSNNTP_ERROR_NO_PERMISSION;
1744
1745 case 503:
1746 return NEWSNNTP_ERROR_PROGRAM_ERROR;
1747
1748 default:
1749 return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
1750 }
1751 }
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
parse_space(char ** line)1771 static int parse_space(char ** line)
1772 {
1773 char * p;
1774
1775 p = * line;
1776
1777 while ((* p == ' ') || (* p == '\t'))
1778 p ++;
1779
1780 if (p != * line) {
1781 * line = p;
1782 return TRUE;
1783 }
1784 else
1785 return FALSE;
1786 }
1787
cut_token(char * line)1788 static char * cut_token(char * line)
1789 {
1790 char * p;
1791 char * p_tab;
1792 char * p_space;
1793
1794 p = line;
1795
1796 p_space = strchr(line, ' ');
1797 p_tab = strchr(line, '\t');
1798 if (p_tab == NULL)
1799 p = p_space;
1800 else if (p_space == NULL)
1801 p = p_tab;
1802 else {
1803 if (p_tab < p_space)
1804 p = p_tab;
1805 else
1806 p = p_space;
1807 }
1808 if (p == NULL)
1809 return NULL;
1810 * p = 0;
1811 p ++;
1812
1813 return p;
1814 }
1815
parse_response(newsnntp * f,char * response)1816 static int parse_response(newsnntp * f, char * response)
1817 {
1818 int code;
1819
1820 code = (int) strtol(response, &response, 10);
1821
1822 if (response == NULL) {
1823 f->nntp_response = NULL;
1824 return code;
1825 }
1826
1827 parse_space(&response);
1828
1829 if (mmap_string_assign(f->nntp_response_buffer, response) != NULL)
1830 f->nntp_response = f->nntp_response_buffer->str;
1831 else
1832 f->nntp_response = NULL;
1833
1834 return code;
1835 }
1836
1837
read_line(newsnntp * f)1838 static char * read_line(newsnntp * f)
1839 {
1840 return mailstream_read_line_remove_eol(f->nntp_stream, f->nntp_stream_buffer);
1841 }
1842
read_multiline(newsnntp * f,size_t size,MMAPString * multiline_buffer)1843 static char * read_multiline(newsnntp * f, size_t size,
1844 MMAPString * multiline_buffer)
1845 {
1846 return mailstream_read_multiline(f->nntp_stream, size,
1847 f->nntp_stream_buffer, multiline_buffer,
1848 f->nntp_progr_rate, f->nntp_progr_fun, f->nntp_progress_fun, f->nntp_progress_context);
1849 }
1850
1851
1852
1853
1854
1855
1856
parse_group_info(char * response,struct newsnntp_group_info ** result)1857 static int parse_group_info(char * response,
1858 struct newsnntp_group_info ** result)
1859 {
1860 char * line;
1861 uint32_t first;
1862 uint32_t last;
1863 uint32_t count;
1864 char * name;
1865 struct newsnntp_group_info * info;
1866
1867 line = response;
1868
1869 count = (uint32_t) strtoul(line, &line, 10);
1870 if (!parse_space(&line))
1871 return FALSE;
1872
1873 first = (uint32_t) strtoul(line, &line, 10);
1874 if (!parse_space(&line))
1875 return FALSE;
1876
1877 last = (uint32_t) strtoul(line, &line, 10);
1878 if (!parse_space(&line))
1879 return FALSE;
1880
1881 name = line;
1882
1883 info = group_info_init(name, first, last, count, FALSE);
1884 if (info == NULL)
1885 return FALSE;
1886
1887 * result = info;
1888
1889 return TRUE;
1890 }
1891
1892
read_groups_list(newsnntp * f)1893 static clist * read_groups_list(newsnntp * f)
1894 {
1895 char * line;
1896 char * group_name;
1897 uint32_t first;
1898 uint32_t last;
1899 uint32_t count;
1900 int type;
1901 clist * groups_list;
1902 struct newsnntp_group_info * n;
1903 int r;
1904
1905 groups_list = clist_new();
1906 if (groups_list == NULL)
1907 goto err;
1908
1909 while (1) {
1910 char * p;
1911
1912 line = read_line(f);
1913 if (line == NULL)
1914 goto free_list;
1915
1916 if (mailstream_is_end_multiline(line))
1917 break;
1918
1919 p = cut_token(line);
1920 if (p == NULL)
1921 continue;
1922
1923 group_name = line;
1924 line = p;
1925
1926 last = (uint32_t)strtol(line, &line, 10);
1927 if (!parse_space(&line))
1928 continue;
1929
1930 first = (uint32_t)strtol(line, &line, 10);
1931 if (!parse_space(&line))
1932 continue;
1933
1934 count = last - first + 1;
1935
1936 type = * line;
1937
1938 n = group_info_init(group_name, first, last, count, type);
1939 if (n == NULL)
1940 goto free_list;
1941
1942 r = clist_append(groups_list, n);
1943 if (r < 0) {
1944 group_info_free(n);
1945 goto free_list;
1946 }
1947 }
1948
1949 return groups_list;
1950
1951 free_list:
1952 group_info_list_free(groups_list);
1953 err:
1954 return NULL;
1955 }
1956
1957
read_headers_list(newsnntp * f)1958 static clist * read_headers_list(newsnntp * f)
1959 {
1960 char * line;
1961 clist * headers_list;
1962 char * header;
1963 int r;
1964
1965 headers_list = clist_new();
1966 if (headers_list == NULL)
1967 goto err;
1968
1969 while (1) {
1970 line = read_line(f);
1971
1972 if (line == NULL)
1973 goto free_list;
1974
1975 if (mailstream_is_end_multiline(line))
1976 break;
1977
1978 header = strdup(line);
1979 if (header == NULL)
1980 goto free_list;
1981
1982 r = clist_append(headers_list, header);
1983 if (r < 0) {
1984 free(header);
1985 goto free_list;
1986 }
1987 }
1988
1989 return headers_list;
1990
1991 free_list:
1992 headers_list_free(headers_list);
1993 err:
1994 return NULL;
1995 }
1996
1997
1998
1999
read_group_time_list(newsnntp * f)2000 static clist * read_group_time_list(newsnntp * f)
2001 {
2002 char * line;
2003 char * group_name;
2004 time_t date;
2005 char * email;
2006 clist * group_time_list;
2007 struct newsnntp_group_time * n;
2008 int r;
2009
2010 group_time_list = clist_new();
2011 if (group_time_list == NULL)
2012 goto err;
2013
2014 while (1) {
2015 char * p;
2016 char * remaining;
2017
2018 line = read_line(f);
2019
2020 if (line == NULL)
2021 goto free_list;
2022
2023 if (mailstream_is_end_multiline(line))
2024 break;
2025
2026 p = cut_token(line);
2027 if (p == NULL)
2028 continue;
2029
2030 date = strtoul(p, &remaining, 10);
2031
2032 p = remaining;
2033 parse_space(&p);
2034
2035 email = p;
2036
2037 group_name = line;
2038
2039 n = group_time_new(group_name, date, email);
2040 if (n == NULL)
2041 goto free_list;
2042
2043 r = clist_append(group_time_list, n);
2044 if (r < 0) {
2045 group_time_free(n);
2046 goto free_list;
2047 }
2048 }
2049
2050 return group_time_list;
2051
2052 free_list:
2053 group_time_list_free(group_time_list);
2054 err:
2055 return NULL;
2056 }
2057
2058
2059
2060
read_distrib_value_meaning_list(newsnntp * f)2061 static clist * read_distrib_value_meaning_list(newsnntp * f)
2062 {
2063 char * line;
2064 char * value;
2065 char * meaning;
2066 clist * distrib_value_meaning_list;
2067 struct newsnntp_distrib_value_meaning * n;
2068 int r;
2069
2070 distrib_value_meaning_list = clist_new();
2071 if (distrib_value_meaning_list == NULL)
2072 goto err;
2073
2074 while (1) {
2075 char * p;
2076
2077 line = read_line(f);
2078 if (line == NULL)
2079 goto free_list;
2080
2081 if (mailstream_is_end_multiline(line))
2082 break;
2083
2084 p = cut_token(line);
2085 if (p == NULL)
2086 continue;
2087
2088 meaning = p;
2089
2090 value = line;
2091
2092 n = distrib_value_meaning_new(value, meaning);
2093 if (n == NULL)
2094 goto free_list;
2095
2096 r = clist_append(distrib_value_meaning_list, n);
2097 if (r < 0) {
2098 distrib_value_meaning_free(n);
2099 goto free_list;
2100 }
2101 }
2102
2103 return distrib_value_meaning_list;
2104
2105 free_list:
2106 distrib_value_meaning_list_free(distrib_value_meaning_list);
2107 err:
2108 return NULL;
2109 }
2110
2111
2112
2113
read_distrib_default_value_list(newsnntp * f)2114 static clist * read_distrib_default_value_list(newsnntp * f)
2115 {
2116 char * line;
2117 uint32_t weight;
2118 char * group_pattern;
2119 char * meaning;
2120 clist * distrib_default_value_list;
2121 struct newsnntp_distrib_default_value * n;
2122 int r;
2123
2124 distrib_default_value_list = clist_new();
2125 if (distrib_default_value_list == NULL)
2126 goto err;
2127
2128 while (1) {
2129 char * p;
2130 char * remaining;
2131
2132 line = read_line(f);
2133 if (line == NULL)
2134 goto free_list;
2135
2136 if (mailstream_is_end_multiline(line))
2137 break;
2138
2139 p = line;
2140
2141 weight = (uint32_t)strtoul(p, &remaining, 10);
2142 p = remaining;
2143 parse_space(&p);
2144
2145 p = cut_token(line);
2146 if (p == NULL)
2147 continue;
2148
2149 meaning = p;
2150 group_pattern = line;
2151
2152 n = distrib_default_value_new(weight, group_pattern, meaning);
2153 if (n == NULL)
2154 goto free_list;
2155
2156 r = clist_append(distrib_default_value_list, n);
2157 if (r < 0) {
2158 distrib_default_value_free(n);
2159 goto free_list;
2160 }
2161 }
2162
2163 return distrib_default_value_list;
2164
2165 free_list:
2166 distrib_default_value_list_free(distrib_default_value_list);
2167 err:
2168 return NULL;
2169 }
2170
2171
2172
read_group_description_list(newsnntp * f)2173 static clist * read_group_description_list(newsnntp * f)
2174 {
2175 char * line;
2176 char * group_name;
2177 char * description;
2178 clist * group_description_list;
2179 struct newsnntp_group_description * n;
2180 int r;
2181
2182 group_description_list = clist_new();
2183 if (group_description_list == NULL)
2184 goto err;
2185
2186 while (1) {
2187 char * p;
2188
2189 line = read_line(f);
2190 if (line == NULL)
2191 goto free_list;
2192
2193 if (mailstream_is_end_multiline(line))
2194 break;
2195
2196 p = cut_token(line);
2197 if (p == NULL)
2198 continue;
2199
2200 description = p;
2201
2202 group_name = line;
2203
2204 n = group_description_new(group_name, description);
2205 if (n == NULL)
2206 goto free_list;
2207
2208 r = clist_append(group_description_list, n);
2209 if (r < 0) {
2210 group_description_free(n);
2211 goto free_list;
2212 }
2213 }
2214
2215 return group_description_list;
2216
2217 free_list:
2218 group_description_list_free(group_description_list);
2219 err:
2220 return NULL;
2221 }
2222
2223
2224
read_subscriptions_list(newsnntp * f)2225 static clist * read_subscriptions_list(newsnntp * f)
2226 {
2227 char * line;
2228 clist * subscriptions_list;
2229 char * group_name;
2230 int r;
2231
2232 subscriptions_list = clist_new();
2233 if (subscriptions_list == NULL)
2234 goto err;
2235
2236 while (1) {
2237 line = read_line(f);
2238
2239 if (line == NULL)
2240 goto free_list;
2241
2242 if (mailstream_is_end_multiline(line))
2243 break;
2244
2245 group_name = strdup(line);
2246 if (group_name == NULL)
2247 goto free_list;
2248
2249 r = clist_append(subscriptions_list, group_name);
2250 if (r < 0) {
2251 free(group_name);
2252 goto free_list;
2253 }
2254 }
2255
2256 return subscriptions_list;
2257
2258 free_list:
2259 subscriptions_list_free(subscriptions_list);
2260 err:
2261 return NULL;
2262 }
2263
2264
2265
read_articles_list(newsnntp * f)2266 static clist * read_articles_list(newsnntp * f)
2267 {
2268 char * line;
2269 clist * articles_list;
2270 uint32_t * article_num;
2271 int r;
2272
2273 articles_list = clist_new();
2274 if (articles_list == NULL)
2275 goto err;
2276
2277 while (1) {
2278 line = read_line(f);
2279 if (line == NULL)
2280 goto free_list;
2281
2282 if (mailstream_is_end_multiline(line))
2283 break;
2284
2285 article_num = malloc(sizeof(* article_num));
2286 if (article_num == NULL)
2287 goto free_list;
2288 * article_num = atoi(line);
2289
2290 r = clist_append(articles_list, article_num);
2291 if (r < 0) {
2292 free(article_num);
2293 goto free_list;
2294 }
2295 }
2296
2297 return articles_list;
2298
2299 free_list:
2300 articles_list_free(articles_list);
2301 err:
2302 return NULL;
2303 }
2304
read_xhdr_resp_list(newsnntp * f)2305 static clist * read_xhdr_resp_list(newsnntp * f)
2306 {
2307 char * line;
2308 uint32_t article;
2309 char * value;
2310 clist * xhdr_resp_list;
2311 struct newsnntp_xhdr_resp_item * n;
2312 int r;
2313
2314 xhdr_resp_list = clist_new();
2315 if (xhdr_resp_list == NULL)
2316 goto err;
2317
2318 while (1) {
2319 line = read_line(f);
2320
2321 if (line == NULL)
2322 goto free_list;
2323
2324 if (mailstream_is_end_multiline(line))
2325 break;
2326
2327 article = (uint32_t) strtoul(line, &line, 10);
2328 if (!parse_space(&line))
2329 continue;
2330
2331 value = line;
2332
2333 n = xhdr_resp_item_new(article, value);
2334 if (n == NULL)
2335 goto free_list;
2336
2337 r = clist_append(xhdr_resp_list, n);
2338 if (r < 0) {
2339 xhdr_resp_item_free(n);
2340 goto free_list;
2341 }
2342 }
2343
2344 return xhdr_resp_list;
2345
2346 free_list:
2347 xhdr_resp_list_free(xhdr_resp_list);
2348 err:
2349 return NULL;
2350 }
2351
2352
read_xover_resp_list(newsnntp * f)2353 static clist * read_xover_resp_list(newsnntp * f)
2354 {
2355 char * line;
2356 clist * xover_resp_list;
2357 struct newsnntp_xover_resp_item * n;
2358 clist * values_list;
2359 clistiter * current;
2360 uint32_t article;
2361 char * subject;
2362 char * author;
2363 char * date;
2364 char * message_id;
2365 char * references;
2366 size_t size;
2367 uint32_t line_count;
2368 clist * others;
2369 int r;
2370
2371 xover_resp_list = clist_new();
2372 if (xover_resp_list == NULL)
2373 goto err;
2374
2375 while (1) {
2376 char * p;
2377
2378 line = read_line(f);
2379
2380 if (line == NULL)
2381 goto free_list;
2382
2383 if (mailstream_is_end_multiline(line))
2384 break;
2385
2386 /* parse the data separated with \t */
2387
2388 values_list = clist_new();
2389 if (values_list == NULL)
2390 goto free_list;
2391
2392 while ((p = strchr(line, '\t')) != NULL) {
2393 * p = 0;
2394 p ++;
2395
2396 r = clist_append(values_list, line);
2397 if (r < 0)
2398 goto free_values_list;
2399 line = p;
2400 }
2401
2402 r = clist_append(values_list, line);
2403 if (r < 0)
2404 goto free_values_list;
2405
2406 /* set the known data */
2407 current = clist_begin(values_list);
2408 if (current == NULL) {
2409 clist_free(values_list);
2410 continue;
2411 }
2412 article = 0;
2413 if (clist_content(current) != NULL) {
2414 article = atoi((char *) clist_content(current));
2415 }
2416
2417 current = clist_next(current);
2418 if (current == NULL) {
2419 clist_free(values_list);
2420 continue;
2421 }
2422 subject = clist_content(current);
2423
2424 current = clist_next(current);
2425 if (current == NULL) {
2426 clist_free(values_list);
2427 continue;
2428 }
2429 author = clist_content(current);
2430
2431 current = clist_next(current);
2432 if (current == NULL) {
2433 clist_free(values_list);
2434 continue;
2435 }
2436 date = clist_content(current);
2437
2438 current = clist_next(current);
2439 if (current == NULL) {
2440 clist_free(values_list);
2441 continue;
2442 }
2443 message_id = clist_content(current);
2444
2445 current = clist_next(current);
2446 if (current == NULL) {
2447 clist_free(values_list);
2448 continue;
2449 }
2450 references = clist_content(current);
2451
2452 current = clist_next(current);
2453 if (current == NULL) {
2454 clist_free(values_list);
2455 continue;
2456 }
2457 size = 0;
2458 if (clist_content(current) != NULL) {
2459 size = atoi((char *) clist_content(current));
2460 }
2461
2462 current = clist_next(current);
2463 if (current == NULL) {
2464 clist_free(values_list);
2465 continue;
2466 }
2467 line_count = 0;
2468 if (clist_content(current) != NULL) {
2469 line_count = atoi((char *) clist_content(current));
2470 }
2471
2472 current = clist_next(current);
2473
2474 /* make a copy of the other data */
2475 others = clist_new();
2476 if (others == NULL) {
2477 goto free_values_list;
2478 }
2479
2480 while (current) {
2481 char * val;
2482 char * original_val;
2483
2484 original_val = clist_content(current);
2485 val = strdup(original_val);
2486 if (val == NULL) {
2487 clist_foreach(others, (clist_func) free, NULL);
2488 clist_free(others);
2489 goto free_list;
2490 }
2491
2492 r = clist_append(others, val);
2493 if (r < 0) {
2494 goto free_list;
2495 }
2496
2497 current = clist_next(current);
2498 }
2499
2500 clist_free(values_list);
2501
2502 n = xover_resp_item_new(article, subject, author, date, message_id,
2503 references, size, line_count, others);
2504 if (n == NULL) {
2505 clist_foreach(others, (clist_func) free, NULL);
2506 clist_free(others);
2507 goto free_list;
2508 }
2509
2510 r = clist_append(xover_resp_list, n);
2511 if (r < 0) {
2512 xover_resp_item_free(n);
2513 goto free_list;
2514 }
2515 }
2516
2517 return xover_resp_list;
2518
2519 free_list:
2520 newsnntp_xover_resp_list_free(xover_resp_list);
2521 err:
2522 return NULL;
2523
2524 free_values_list:
2525 clist_foreach(values_list, (clist_func) free, NULL);
2526 clist_free(values_list);
2527 return NULL;
2528 }
2529
send_command(newsnntp * f,char * command)2530 static int send_command(newsnntp * f, char * command)
2531 {
2532 return send_command_private(f, command, 1);
2533 }
2534
send_command_private(newsnntp * f,char * command,int can_be_published)2535 static int send_command_private(newsnntp * f, char * command, int can_be_published)
2536 {
2537 ssize_t r;
2538
2539 mailstream_set_privacy(f->nntp_stream, can_be_published);
2540 r = mailstream_write(f->nntp_stream, command, strlen(command));
2541 if (r == -1)
2542 return -1;
2543
2544 r = mailstream_flush(f->nntp_stream);
2545 if (r == -1)
2546 return -1;
2547
2548 return 0;
2549 }
2550
nntp_logger(mailstream * s,int log_type,const char * str,size_t size,void * context)2551 static inline void nntp_logger(mailstream * s, int log_type,
2552 const char * str, size_t size, void * context)
2553 {
2554 newsnntp * session;
2555
2556 session = context;
2557 if (session->nntp_logger == NULL)
2558 return;
2559
2560 session->nntp_logger(session, log_type, str, size, session->nntp_logger_context);
2561 }
2562
newsnntp_set_logger(newsnntp * session,void (* logger)(newsnntp * session,int log_type,const char * str,size_t size,void * context),void * logger_context)2563 void newsnntp_set_logger(newsnntp * session, void (* logger)(newsnntp * session, int log_type,
2564 const char * str, size_t size, void * context), void * logger_context)
2565 {
2566 session->nntp_logger = logger;
2567 session->nntp_logger_context = logger_context;
2568 }
2569
newsnntp_set_progress_callback(newsnntp * f,mailprogress_function * progr_fun,void * context)2570 void newsnntp_set_progress_callback(newsnntp * f, mailprogress_function * progr_fun, void * context)
2571 {
2572 f->nntp_progress_fun = progr_fun;
2573 f->nntp_progress_context = context;
2574 }
2575