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