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