00001
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "defines.h"
00023
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028 #include <time.h>
00029 #include <errno.h>
00030
00031 #include <sys/stat.h>
00032 #include <sys/types.h>
00033 #include <sys/time.h>
00034
00035
00036 #include <sys/socket.h>
00037 #include <netdb.h>
00038 #include <unistd.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041
00042 #include <pthread.h>
00043
00044 #include "cf_pthread.h"
00045
00046 #include "hashlib.h"
00047 #include "utils.h"
00048 #include "configparser.h"
00049 #include "readline.h"
00050 #include "fo_server.h"
00051 #include "charconvert.h"
00052 #include "serverlib.h"
00053
00054
00055
00057 #define flt_nntp_syntax_error() writen(sock,"501 command syntax error\015\012",26)
00058
00060 #define flt_nntp_cleanup_req() do { \
00061 while(tnum--) free(tokens[tnum]); \
00062 free(tokens); \
00063 free(line); \
00064 } while(0)
00065
00067 #define CtoI(n) (n-'0')
00068
00070 #define days_in_year(y) ((y) % 4 ? 365 : (y) % 100 ? 366 : (y) % 400 ? 365 : 366)
00071
00073 #define flt_nntp_is_delim(c) (isspace(c) || (c) == ':' || (c) == '=')
00074
00075
00076 static u_char *NNTPInterface = NULL;
00077 static u_char *NNTPHost = NULL;
00078 static u_char *NNTPGroupName = NULL;
00079 static unsigned int NNTPPort = 0;
00080 static int NNTPMayPost = 0;
00082 struct sockaddr_in *NNTP_Addr = NULL;
00084 u_char *html_decode(const u_char *str) {
00085 t_name_value *cs = cfg_get_value(&fo_default_conf,"ExternCharset");
00086 u_char *new_str;
00087 register u_char *ptr;
00088 t_string ns;
00089
00090 str_init(&ns);
00091
00092 if(cs) {
00093 if(cf_strcmp(cs->values[0],"UTF-8")) {
00094 if((new_str = charset_convert(str,strlen(str),"UTF-8",cs->values[0],NULL)) == NULL) {
00095 new_str = strdup(str);
00096 }
00097 }
00098 else {
00099 new_str = strdup(str);
00100 }
00101 }
00102 else {
00103 new_str = strdup(str);
00104 }
00105
00106 for(ptr = new_str;*ptr;ptr++) {
00107 if(*ptr == '&') {
00108 if(cf_strncmp(ptr,">",4) == 0) {
00109 str_char_append(&ns,'>');
00110 }
00111 else if(cf_strncmp(ptr,"<",4) == 0) {
00112 str_char_append(&ns,'<');
00113 }
00114 else if(cf_strncmp(ptr,"&",5) == 0) {
00115 str_char_append(&ns,'&');
00116 }
00117 else if(cf_strncmp(ptr,""",6) == 0) {
00118 str_char_append(&ns,'"');
00119 }
00120 else if(cf_strncmp(ptr," ",6) == 0) {
00121 str_char_append(&ns,'\240');
00122 }
00123 }
00124 }
00125
00126 free(new_str);
00127 return ns.content;
00128 }
00129
00136 int flt_nntp_tokenize(u_char *line,u_char ***tokens) {
00137 int n = 0,reser = 5;
00138 register u_char *ptr,*prev;
00139
00140 *tokens = fo_alloc(NULL,5,sizeof(u_char **),FO_ALLOC_MALLOC);
00141 if(!*tokens) return 0;
00142
00143 for(prev=ptr=line;*ptr;ptr++) {
00144 if(n >= reser) {
00145 reser += 5;
00146 *tokens = fo_alloc(*tokens,reser,sizeof(u_char **),FO_ALLOC_REALLOC);
00147 }
00148
00149 if(flt_nntp_is_delim(*ptr)) {
00150 if((ptr - 1 == prev && flt_nntp_is_delim(*(ptr-1))) || ptr == prev) {
00151 prev = ptr;
00152 continue;
00153 }
00154
00155 *ptr = 0;
00156 (*tokens)[n++] = strdup(prev);
00157 prev = ptr+1;
00158 }
00159 }
00160
00161 if(prev != ptr && (prev-1 != ptr || !flt_nntp_is_delim(*(ptr-1))) && *ptr) (*tokens)[n++] = strdup(prev);
00162
00163 return n;
00164 }
00165
00172 time_t flt_nntp_parse_date(u_char *t1,u_char *t2) {
00173 static int days_in_month[12] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
00174 register u_char *p;
00175 int century, year, month, day, hour, mins, secs, datelen;
00176 register int i;
00177 long seconds;
00178 u_char buff[8 + 6 + 1];
00179 struct tm current;
00180 struct timeval now;
00181
00182 datelen = strlen(t1);
00183 if((datelen < 6 || datelen > 8) || strlen(t2) != 6) return -1;
00184
00185 sprintf(buff,"%s%s",t1,t2);
00186
00187 for(p=buff;*p;p++) {
00188 if(!isdigit(*p)) return -1;
00189 }
00190
00191 p = buff + datelen - 6;
00192
00193 year = CtoI(p[0]) * 10 + CtoI(p[1]);
00194 month = CtoI(p[2]) * 10 + CtoI(p[3]);
00195 day = CtoI(p[4]) * 10 + CtoI(p[5]);
00196 hour = CtoI(p[6]) * 10 + CtoI(p[7]);
00197 mins = CtoI(p[8]) * 10 + CtoI(p[9]);
00198 secs = CtoI(p[10]) * 10 + CtoI(p[11]);
00199
00200 if(datelen == 6) {
00201 if(gettimeofday(&now,NULL) == -1 || gmtime_r(&now.tv_sec,¤t) == NULL) return -1;
00202
00203 century = current.tm_year / 100;
00204 if(current.tm_year >= 100) current.tm_year -= century * 100;
00205
00206 if(year <= current.tm_year) year += (century + 19) * 100;
00207 else year += (century + 18) * 100;
00208 }
00209 else {
00210 year += CtoI(*--p) * 100;
00211 if(datelen == 7) year += 1900;
00212 else year += CtoI(*--p) * 1000;
00213 }
00214
00215 if(month < 1 || month > 12 || day < 1 || day > 31 || mins < 0 || mins > 59 || secs < 0 || secs > 59) return -1;
00216
00217 if(hour == 24) {
00218 hour = 0;
00219 day++;
00220 }
00221 else {
00222 if(hour < 0 || hour > 23) return -1;
00223 }
00224
00225 for(seconds = 0, i = 1970; i < year; i++) seconds += days_in_year(i);
00226 if(days_in_year(year) == 366 && month > 2) seconds++;
00227
00228 while(--month > 0) seconds += days_in_month[month];
00229
00230 seconds += day - 1;
00231 seconds = 24 * seconds + hour;
00232 seconds = 60 * seconds + mins;
00233 seconds = 60 * seconds + secs;
00234
00235 return seconds;
00236 }
00237
00243 int flt_nntp_set_us_up_the_socket(struct sockaddr_in *addr) {
00244 int sock,ret,one = 1;
00245
00246 if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1) {
00247 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: socket: %s\n",sock,strerror(errno));
00248 return -1;
00249 }
00250
00251 if((setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one))) == -1) {
00252 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: setsockopt(SO_REUSEADDR): %s\n",strerror(errno));
00253 close(sock);
00254 return -1;
00255 }
00256
00257 memset(addr,0,sizeof(struct sockaddr_in));
00258 addr->sin_family = AF_INET;
00259 addr->sin_port = htons(NNTPPort);
00260
00261 if(NNTPInterface) {
00262 if((ret = inet_aton(NNTPInterface,&(addr->sin_addr))) != 0) {
00263 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: inet_aton(\"%s\"): %s\n",NNTPInterface,strerror(ret));
00264 close(sock);
00265 return -1;
00266 }
00267 }
00268 else {
00269 addr->sin_addr.s_addr = htonl(INADDR_ANY);
00270 }
00271
00272 if(bind(sock,(struct sockaddr *)addr,sizeof(struct sockaddr_in)) < 0) {
00273 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: bind: %s\n",strerror(errno));
00274 close(sock);
00275 return -1;
00276 }
00277
00278 if(listen(sock,LISTENQ) != 0) {
00279 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: listen: %s\n",strerror(errno));
00280 close(sock);
00281 return -1;
00282 }
00283
00284 return sock;
00285 }
00286
00295 int flt_nntp_get_article_pointer(t_thread **t,t_posting **p,long *anum,long num) {
00296 t_thread *t1;
00297
00298 *t = NULL;
00299 *p = NULL;
00300
00301
00302
00303 CF_RW_RD(&head.lock);
00304 *t = head.thread;
00305 CF_RW_UN(&head.lock);
00306
00307 CF_RW_RD(&((*t)->lock));
00308 *p = (*t)->postings;
00309 CF_RW_UN(&((*t)->lock));
00310
00311 *anum = 0;
00312
00313 if(*anum == num) return 0;
00314
00315
00316
00317 for(t1=NULL;*t;*t=t1) {
00318 CF_RW_RD(&((*t)->lock));
00319
00320
00321 if(t1) *p = (*t)->postings;
00322
00323
00324 for(;*p && *anum < num;*p=(*p)->next,*anum += 1);
00325
00326
00327 if(*anum == num) {
00328 if(!*p) {
00329 t1 = (*t)->next;
00330 CF_RW_UN(&((*t)->lock));
00331 *t = t1;
00332
00333 if(*t) {
00334 CF_RW_RD(&((*t))->lock);
00335 *p = (*t)->postings;
00336 }
00337 else {
00338 return -1;
00339 }
00340 }
00341
00342 break;
00343 }
00344
00345 t1 = (*t)->next;
00346 CF_RW_UN(&((*t)->lock));
00347 *t = t1;
00348 }
00349
00350 if(*t && *p) return 0;
00351 else return -1;
00352
00353
00354 return -1;
00355 }
00356
00361 int flt_nntp_count(void) {
00362 int cnt = 0;
00363 t_thread *t,*t1;
00364 t_posting *p;
00365
00366 CF_RW_RD(&head.lock);
00367 t = head.thread;
00368 CF_RW_UN(&head.lock);
00369
00370 while(t) {
00371 CF_RW_RD(&t->lock);
00372
00373 for(p=t->postings;p;p=p->next) cnt++;
00374
00375 t1 = t->next;
00376 CF_RW_UN(&t->lock);
00377 t = t1;
00378 }
00379
00380 return cnt;
00381 }
00382
00388 long flt_nntp_count_newlines(const t_posting *p1) {
00389 u_char *tmp = p1->content;
00390 long count = 0;
00391
00392 while((tmp = strstr(tmp+1,"<br />")) != 0) ++count;
00393
00394 return count;
00395 }
00396
00404 void flt_nntp_send_body(const t_thread *t,const t_posting *p,int sock,int dot) {
00405 t_string str;
00406 u_char *ptr,*content;
00407
00408 str_init(&str);
00409
00410 for(ptr=p->content;*ptr;ptr++) {
00411 if(cf_strncmp(ptr,"<br />",6) == 0) {
00412 str_chars_append(&str,"\015\012",2);
00413 ptr += 5;
00414 }
00415 else if(cf_strncmp(ptr,"<a href=\"",9) == 0) {
00416 u_char *tmp;
00417
00418 ptr += 9;
00419 tmp = strstr(ptr,"\"");
00420
00421 if(tmp) {
00422 str_char_append(&str,'<');
00423 str_chars_append(&str,ptr,tmp-ptr);
00424 str_char_append(&str,'>');
00425
00426 for(;cf_strncmp(ptr+1,"</a>",4) != 0;ptr++);
00427 ptr += 4;
00428 }
00429 else {
00430 tmp -= 9;
00431 }
00432 }
00433 else if(cf_strncmp(ptr,"<img src=\"",10) == 0) {
00434 u_char *tmp;
00435
00436 ptr += 10;
00437 tmp = strstr(ptr,"\"");
00438
00439 if(tmp) {
00440 str_char_append(&str,'<');
00441 str_chars_append(&str,ptr,tmp-ptr);
00442 str_char_append(&str,'>');
00443
00444 ptr = strstr(tmp,">");
00445 }
00446 else {
00447 ptr -= 10;
00448 }
00449 }
00450 else if(cf_strncmp(ptr,"[pref:",6) == 0) {
00451 u_char *tmp;
00452 u_char buff[512];
00453 long i;
00454 u_int64_t tid,mid;
00455
00456 ptr += 6;
00457 tid = strtoull(ptr,(char **)&tmp,10);
00458 mid = strtoull(tmp+5,(char **)&tmp,10);
00459
00460 i = snprintf(buff,512,"<t%lldm%lld@%s>",tid,mid,NNTPHost);
00461
00462 ptr = tmp;
00463 }
00464 else if(*ptr == (u_char)127) {
00465 str_char_append(&str,'>');
00466 }
00467 else if(cf_strncmp(ptr,"_/_SIG_/_",9) == 0) {
00468 str_chars_append(&str,"-- \015\012",9);
00469 ptr += 8;
00470 }
00471 else {
00472 str_char_append(&str,*ptr);
00473 }
00474 }
00475
00476 str_chars_append(&str,"\015\012",2);
00477
00478 if(dot) str_chars_append(&str,".\015\012",3);
00479
00480 content = html_decode(str.content);
00481
00482 writen(sock,content,strlen(content));
00483
00484 free(str.content);
00485 free(content);
00486 }
00487
00496 void flt_nntp_send_headers(const t_thread *t,const t_posting *p1,int sock,long anum,int newline) {
00497 t_string str;
00498 u_char buff[250];
00499 struct tm tm;
00500 int i;
00501
00502 str_init(&str);
00503
00504 if(p1->user.email) {
00505 str_chars_append(&str,"From: \"",7);
00506 str_chars_append(&str,p1->user.name,p1->user.name_len);
00507 str_chars_append(&str,"\" ",2);
00508
00509 str_char_append(&str,'<');
00510 str_chars_append(&str,p1->user.email,p1->user.email_len);
00511 str_char_append(&str,'>');
00512 }
00513 else {
00514 str_chars_append(&str,"From: ",6);
00515 str_chars_append(&str,p1->user.name,p1->user.name_len);
00516 }
00517
00518 str_chars_append(&str,"\015\012Newsgroups: ",14);
00519 str_chars_append(&str,NNTPGroupName,strlen(NNTPGroupName));
00520 str_chars_append(&str,"\015\012Subject: ",11);
00521 str_chars_append(&str,p1->subject,p1->subject_len);
00522 str_chars_append(&str,"\015\012Message-ID: ",14);
00523
00524 i = snprintf(buff,250,"<t%lldm%lld@%s>",t->tid,p1->mid,NNTPHost);
00525 str_chars_append(&str,buff,i);
00526 if(p1->category) {
00527 str_chars_append(&str,"\015\012X-Category: ",14);
00528 str_chars_append(&str,p1->category,p1->category_len);
00529 }
00530
00531 if(p1->user.hp) {
00532 str_chars_append(&str,"\015\012X-Homepage: ",14);
00533 str_chars_append(&str,p1->user.hp,p1->user.hp_len);
00534 }
00535
00536 if(p1->user.img) {
00537 str_chars_append(&str,"\015\012X-Image: ",11);
00538 str_chars_append(&str,p1->user.img,p1->user.img_len);
00539 }
00540
00541 gmtime_r(&p1->date,&tm);
00542 str_chars_append(&str,"\015\012Date: ",8);
00543 i = strftime(buff,250,"%a, %d %b %Y %T %z (GMT)",&tm);
00544 str_chars_append(&str,buff,i);
00545
00546 if(p1->prev) {
00547 t_posting *p2 = (t_posting *)p1;
00548
00549 while(p2->prev && p2->level >= p1->level) p2 = p2->prev;
00550
00551 if(p2) {
00552 str_chars_append(&str,"\015\012In-Reply-To: ",14);
00553 i = snprintf(buff,512,"<t%lldm%lld@%s>",t->tid,p2->mid,NNTPHost);
00554 str_chars_append(&str,buff,i);
00555 }
00556 }
00557
00558 str_chars_append(&str,"\015\012Xref: ",8);
00559 i = snprintf(buff,512,"%s %s:%ld\015\012",NNTPHost,NNTPGroupName,anum);
00560 str_chars_append(&str,buff,i);
00561
00562
00563 str_chars_append(&str,"Lines: ",7);
00564 i = snprintf(buff,512,"%ld",flt_nntp_count_newlines(p1)+1);
00565 str_chars_append(&str,buff,i);
00566 str_chars_append(&str,"\015\012",2);
00567
00568 if(newline) str_chars_append(&str,"\015\012",2);
00569
00570 writen(sock,str.content,str.len);
00571 free(str.content);
00572 }
00573
00579 void send_new_news(int sock,time_t date) {
00580 t_string str;
00581 size_t w;
00582 t_thread *t,*t1;
00583 t_posting *p;
00584 u_char buff[100];
00585
00586 str_init(&str);
00587
00588 CF_RW_RD(&head.lock);
00589 t = head.thread;
00590 CF_RW_UN(&head.lock);
00591
00592 for(;t;t=t1) {
00593 CF_RW_RD(&t->lock);
00594
00595 for(p=t->postings;p;p=p->next) {
00596 if(p->date >= date) {
00597 w = snprintf(buff,100,"<t%lldm%lld@%s>\015\012",t->tid,p->mid,NNTPHost);
00598 str_chars_append(&str,buff,w);
00599 }
00600 }
00601
00602 t1 = t->next;
00603 CF_RW_UN(&t->lock);
00604 }
00605
00606 str_chars_append(&str,".\015\012",3);
00607 writen(sock,str.content,str.len);
00608
00609 str_cleanup(&str);
00610 }
00611
00616 void flt_nntp_handle_request(int sock) {
00617 rline_t tsd;
00618 u_char *line;
00619 u_char **tokens;
00620 int ShallRun = 1;
00621 long anum = 0,tnum = 0;
00622 t_thread *t = NULL;
00623 t_posting *p = NULL;
00624
00625 memset(&tsd,0,sizeof(rline_t));
00626
00627 writen(sock,"200 Classic Forum NNTP plugin ready - posting not yet implemented\015\012",67);
00628
00629 while(ShallRun) {
00630 line = readline(sock,&tsd);
00631
00632 #ifdef DEBUG
00633 cf_log(LOG_DBG,__FILE__,__LINE__,"flt_nntp: line: '%s'\n",line);
00634 #endif
00635
00636 if(line) {
00637 tnum = flt_nntp_tokenize(line,&tokens);
00638
00639 if(tnum) {
00640 if(cf_strcasecmp(tokens[0],"ARTICLE") == 0) {
00641 u_char *tmp;
00642
00643 if(tnum < 2) {
00644 flt_nntp_syntax_error();
00645 flt_nntp_cleanup_req();
00646 continue;
00647 }
00648
00649 if(*tokens[1] == '<') {
00650 t_thread *t1;
00651 t_posting *p1;
00652
00653 if((t1 = cf_get_thread(strtoull(tokens[1]+1,(char **)&tmp,10))) != NULL) {
00654 if((p1 = cf_get_posting(t1,strtoull(tmp+1,NULL,10))) != NULL) {
00655 u_char buff[512];
00656 int i;
00657
00658 i = snprintf(buff,512,"220 %ld <t%lldm%lld@%s> Article retrieved, everything follows\015\012",anum+1,t->tid,p->mid,NNTPHost);
00659
00660 writen(sock,buff,i);
00661 flt_nntp_send_headers(t1,p1,sock,anum+1,1);
00662 flt_nntp_send_body(t1,p1,sock,1);
00663 }
00664 }
00665 }
00666 else {
00667 long i,num = strtol(tokens[1],NULL,10);
00668
00669 if(flt_nntp_get_article_pointer(&t,&p,&anum,num?num-1:0) == 0) {
00670 u_char buff[512];
00671
00672 i = snprintf(buff,512,"220 %ld <t%lldm%lld@%s> Article retrieved, text follows\015\012",num,t->tid,p->mid,NNTPHost);
00673 writen(sock,buff,i);
00674 flt_nntp_send_headers(t,p,sock,num,1);
00675 flt_nntp_send_body(t,p,sock,1);
00676
00677 CF_RW_UN(&t->lock);
00678 }
00679 else {
00680 writen(sock,"430 no such article found\015\012",27);
00681 }
00682 }
00683 }
00684
00685 else if(cf_strcasecmp(tokens[0],"BODY") == 0) {
00686 if(*tokens[1] == '<') {
00687 }
00688 else {
00689 u_char buff[512];
00690 int i;
00691 long num = strtol(tokens[1],NULL,10);
00692
00693 if(flt_nntp_get_article_pointer(&t,&p,&anum,num?num-1:0) == 0) {
00694 CF_RW_RD(&t->lock);
00695
00696 i = snprintf(buff,512,"222 %ld <t%lldm%lld@%s> article retrieved - body follows\015\012",anum+1,t->tid,p->mid,NNTPHost);
00697 writen(sock,buff,i);
00698 flt_nntp_send_body(t,p,sock,1);
00699
00700 CF_RW_UN(&t->lock);
00701 }
00702 else {
00703 writen(sock,"430 no such article found\015\012",27);
00704 }
00705 }
00706 }
00707
00708 else if(cf_strcasecmp(tokens[0],"MODE") == 0) {
00709 if(tnum != 2) {
00710 flt_nntp_syntax_error();
00711 flt_nntp_cleanup_req();
00712 continue;
00713 }
00714
00715 if(cf_strcasecmp(tokens[1],"reader") == 0) {
00716 writen(sock,"200 Ok, go and read\015\012",21);
00717 }
00718 else {
00719 writen(sock,"500 hey, no streaming mode allowed!\015\012",37);
00720 }
00721 }
00722
00723 else if(cf_strcasecmp(tokens[0],"HEAD") == 0) {
00724 if(*tokens[1] == '<') {
00725 }
00726 else {
00727 long x = strtol(tokens[1],NULL,10);
00728 int i;
00729 u_char buff[512];
00730
00731 if(flt_nntp_get_article_pointer(&t,&p,&anum,x?x-1:0) == 0) {
00732 i = snprintf(buff,512,"221 %ld <t%lldm%lld@%s> head follows\015\012",anum+1,t->tid,p->mid,NNTPHost);
00733 writen(sock,buff,i);
00734 flt_nntp_send_headers(t,p,sock,anum+1,0);
00735 writen(sock,".\015\012",3);
00736 }
00737 else {
00738 writen(sock,"430 no such article found\015\012",27);
00739 }
00740 }
00741 }
00742
00743 else if(cf_strncmp(line,"STAT",4) == 0) {
00744 if(tnum < 2) {
00745 flt_nntp_syntax_error();
00746 flt_nntp_cleanup_req();
00747 continue;
00748 }
00749
00750 CF_RW_RD(&head.lock);
00751 if(1) {
00752 long i = 0,num = strtol(tokens[1],NULL,10);
00753
00754 if(flt_nntp_get_article_pointer(&t,&p,&anum,num?num-1:0) == 0) {
00755 u_char buff[512];
00756
00757 i = snprintf(buff,512,"230 %ld <t%lldm%lld@%s> Article retrieved - statistics only (article %ld selecetd, its message-id is <t%lldm%lld@%s>)\015\012",num,t->tid,p->mid,NNTPHost,num,t->tid,p->mid,NNTPHost);
00758 writen(sock,buff,i);
00759 CF_RW_UN(&t->lock);
00760 }
00761 else {
00762 writen(sock,"430 no such article found\015\012",27);
00763 }
00764
00765 CF_RW_UN(&head.lock);
00766 }
00767 }
00768
00769 else if(cf_strcasecmp(tokens[0],"GROUP") == 0) {
00770 if(tnum < 2) {
00771 flt_nntp_syntax_error();
00772 flt_nntp_cleanup_req();
00773 continue;
00774 }
00775
00776 if(cf_strcmp(tokens[1],NNTPGroupName) == 0) {
00777 int n = flt_nntp_count();
00778 u_char buff[512];
00779
00780 n = snprintf(buff,512,"211 %d 1 %d %s group selected\015\012",n,n,NNTPGroupName);
00781 writen(sock,buff,n);
00782
00783 CF_RW_RD(&head.lock);
00784 t = head.thread;
00785 CF_RW_UN(&head.lock);
00786
00787 if(t) {
00788 CF_RW_RD(&t->lock);
00789 p = head.thread->postings;
00790 CF_RW_UN(&t->lock);
00791 }
00792 }
00793 else {
00794 writen(sock,"411 I don't know this group.\015\012",30);
00795 }
00796 }
00797
00798 else if(cf_strcasecmp(tokens[0],"LAST") == 0) {
00799 int i = 0;
00800 u_char buff[512];
00801
00802 if(!t || !p) {
00803 writen(sock,"421 no last article in this group\015\012",35);
00804 flt_nntp_cleanup_req();
00805 continue;
00806 }
00807
00808 CF_RW_RD(&t->lock);
00809
00810 if(p->prev) {
00811 p = p->prev;
00812 }
00813 else {
00814 if(t->prev) {
00815 t_thread *t1;
00816
00817 CF_RW_RD(&t->prev->lock);
00818 t1 = t->prev;
00819 CF_RW_UN(&t->lock);
00820 t = t1;
00821 p = t->last;
00822 }
00823 else {
00824 writen(sock,"421 no last article in this group\015\012",35);
00825 flt_nntp_cleanup_req();
00826 CF_RW_UN(&t->lock);
00827 continue;
00828 }
00829 }
00830
00831 i = snprintf(buff,512,"223 %ld <t%lldm%lld@%s> article retrieved - request text seperately\015\012",--anum,t->tid,p->mid,NNTPHost);
00832 writen(sock,buff,i);
00833
00834 CF_RW_UN(&t->lock);
00835 }
00836
00837 else if(cf_strcasecmp(tokens[0],"NEXT") == 0) {
00838 u_char buff[512];
00839 int i;
00840
00841 if(!p) {
00842 if(!t) {
00843 CF_RW_RD(&head.lock);
00844 t = head.thread;
00845 CF_RW_UN(&head.lock);
00846 }
00847
00848 CF_RW_RD(&t->lock);
00849 p = t->postings;
00850 CF_RW_UN(&t->lock);
00851 }
00852
00853 CF_RW_RD(&t->lock);
00854
00855 if(!p->next) {
00856 if(!t->next) {
00857 writen(sock,"421 No next article in group\015\012",30);
00858 CF_RW_UN(&t->lock);
00859 flt_nntp_cleanup_req();
00860 continue;
00861 }
00862 else {
00863 t_thread *t2 = t->next;
00864 CF_RW_UN(&t->lock);
00865 t = t2;
00866
00867 CF_RW_RD(&t->lock);
00868 p = t->postings;
00869 }
00870 }
00871 else {
00872 p = p->next;
00873 }
00874
00875 i = snprintf(buff,512,"223 %ld <t%lldm%lld@%s> article retrieved - request text seperately\015\012",++anum,t->tid,p->mid,NNTPHost);
00876 writen(sock,buff,i);
00877
00878 CF_RW_UN(&t->lock);
00879
00880 }
00881
00882 else if(cf_strcasecmp(tokens[0],"LIST") == 0) {
00883 int cnt = 0;
00884 u_char buff[250];
00885
00886 cnt = flt_nntp_count();
00887 cnt = snprintf(buff,250,"%s %d 1 n\015\012.\015\012",NNTPGroupName,cnt);
00888 writen(sock,"215 I'm pleased to serve you\015\012",30);
00889 writen(sock,buff,cnt);
00890 }
00891
00892 else if(cf_strcasecmp(tokens[0],"NEWGROUPS") == 0) {
00893
00894 writen(sock,"231 List of new newsgroups follows\015\012.\015\012",39);
00895 }
00896
00897 else if(cf_strncmp(line,"NEWNEWS",7) == 0) {
00898 u_char *group;
00899 time_t date;
00900
00901 if(tnum < 4) {
00902 flt_nntp_syntax_error();
00903 flt_nntp_cleanup_req();
00904 continue;
00905 }
00906
00907 group = tokens[1];
00908
00909 if(*group == '*' || cf_strncmp(group,NNTPGroupName,strlen(NNTPGroupName)) == 0) {
00910
00911 if((date = flt_nntp_parse_date(tokens[2],tokens[3])) < 0) {
00912 writen(sock,"501 command syntax error\015\012",26);
00913 }
00914 else {
00915 if(tnum < 5) {
00916 struct tm local,gmt;
00917 time_t now;
00918 long tz;
00919
00920 if(gmtime_r(&now,&gmt) == NULL || localtime_r(&now,&local) == NULL) {
00921 writen(sock,"501 command syntax error\015\012",26);
00922 }
00923 else {
00924 tz = (gmt.tm_hour - local.tm_hour) * 60 + gmt.tm_min - local.tm_min;
00925 date += tz;
00926
00927 writen(sock,"230 list of new articles by message-id follows\015\012",48);
00928 send_new_news(sock,date);
00929 }
00930 }
00931 }
00932 }
00933 else {
00934 writen(sock,"411 no such newsgroup\015\012",23);
00935 }
00936
00937 }
00938
00939 else if(cf_strcasecmp(tokens[0],"POST") == 0) {
00940 }
00941
00942 else if(cf_strcasecmp(tokens[0],"QUIT") == 0) {
00943 writen(sock,"205 Go away!\015\012",14);
00944 ShallRun = 0;
00945 }
00946 else {
00947 writen(sock,"500 Hu? Go and read RFC 977\015\012",29);
00948 }
00949
00950
00951 flt_nntp_cleanup_req();
00952 }
00953 }
00954 else {
00955 ShallRun = 0;
00956 }
00957 }
00958
00959 close(sock);
00960 }
00961
00967 int flt_nntp_run(int main_sock) {
00968 int sock;
00969
00970 if(!NNTPPort) {
00971 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: we need a port to bind on!\n");
00972 return FLT_EXIT;
00973 }
00974 if(!NNTPHost) {
00975 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: we need a hostname!\n");
00976 return FLT_EXIT;
00977 }
00978
00979 if(!NNTPGroupName) NNTPGroupName = strdup("alt.cforum");
00980
00981
00982 NNTP_Addr = calloc(1,sizeof(struct sockaddr_in));
00983 sock = flt_nntp_set_us_up_the_socket(NNTP_Addr);
00984
00985 if(sock < 0) return FLT_EXIT;
00986
00987 if(cf_push_server(sock,(struct sockaddr *)NNTP_Addr,sizeof(struct sockaddr_in),flt_nntp_handle_request) != 0) {
00988 cf_log(LOG_ERR,__FILE__,__LINE__,"cf_push_server returned not 0!\n");
00989 return FLT_EXIT;
00990 }
00991
00992 return FLT_OK;
00993 }
00994
01004 int flt_nntp_handle_command(t_configfile *cf,t_conf_opt *opt,u_char **args,int argnum) {
01005 if(argnum == 1) {
01006 if(cf_strcmp(opt->name,"NNTPInterface") == 0) {
01007 if(NNTPInterface) free(NNTPInterface);
01008 NNTPInterface = strdup(args[0]);
01009 }
01010 else if(cf_strcmp(opt->name,"NNTPHost") == 0) {
01011 if(NNTPHost) free(NNTPHost);
01012 NNTPHost = strdup(args[0]);
01013 }
01014 else if(cf_strcmp(opt->name,"NNTPMayPost") == 0) {
01015 if(cf_strcasecmp(args[0],"YES") == 0) NNTPMayPost = 1;
01016 }
01017 else if(cf_strcmp(opt->name,"NNTPGroupName") == 0) {
01018 if(NNTPGroupName) free(NNTPGroupName);
01019 NNTPGroupName = strdup(args[0]);
01020 }
01021 else {
01022 if((NNTPPort = (unsigned int)strtol(args[0],NULL,10)) <= 1024) {
01023 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: Sorry, ports <= 1024 are not supported. Reasonable would be something\nlike 2048 or 4096.\n");
01024 return 1;
01025 }
01026 }
01027 }
01028 else {
01029 cf_log(LOG_ERR,__FILE__,__LINE__,"flt_nntp: Directive %s expects one argument!\n",opt->name);
01030 return 1;
01031 }
01032
01033 return 0;
01034 }
01035
01039 void flt_nntp_cleanup(void) {
01040 if(NNTPInterface) free(NNTPInterface);
01041 if(NNTPHost) free(NNTPHost);
01042 if(NNTPGroupName) free(NNTPGroupName);
01043 if(NNTP_Addr) free(NNTP_Addr);
01044 }
01045
01049 t_conf_opt flt_nntp_config[] = {
01050 { "NNTPPort", flt_nntp_handle_command, NULL },
01051 { "NNTPInterface", flt_nntp_handle_command, NULL },
01052 { "NNTPHost", flt_nntp_handle_command, NULL },
01053 { "NNTPMayPost", flt_nntp_handle_command, NULL },
01054 { "NNTPGroupName", flt_nntp_handle_command, NULL },
01055 { NULL, NULL, NULL }
01056 };
01057
01061 t_handler_config flt_nntp_handlers[] = {
01062 { INIT_HANDLER, flt_nntp_run },
01063 { 0, NULL }
01064 };
01065
01069 t_module_config flt_nntp = {
01070 flt_nntp_config,
01071 flt_nntp_handlers,
01072 NULL,
01073 NULL,
01074 NULL,
01075 flt_nntp_cleanup
01076 };
01077
01078