Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

flt_nntp.c

Go to the documentation of this file.
00001 
00011 /* {{{ Initial comments */
00012 /*
00013  * $LastChangedDate: 2004-04-01 18:34:17 +0200 (Thu, 01 Apr 2004) $
00014  * $LastChangedRevision: 50 $
00015  * $LastChangedBy: ckruse $
00016  *
00017  */
00018 /* }}} */
00019 
00020 /* {{{ Includes */
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 /* socket includes */
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,"&gt;",4) == 0) {
00109         str_char_append(&ns,'>');
00110       }
00111       else if(cf_strncmp(ptr,"&lt;",4) == 0) {
00112         str_char_append(&ns,'<');
00113       }
00114       else if(cf_strncmp(ptr,"&amp;",5) == 0) {
00115         str_char_append(&ns,'&');
00116       }
00117       else if(cf_strncmp(ptr,"&quot;",6) == 0) {
00118         str_char_append(&ns,'"');
00119       }
00120       else if(cf_strncmp(ptr,"&nbsp;",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,&current) == 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; /* YYYMMDD */
00212     else year += CtoI(*--p) * 1000; /* YYYYMMDD */
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   /* ah :) first call */
00302   /* due to archiver runs it alwas has to be the first run... */
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   /* since we're not yet at 'num', we have to go _forwards_ */
00317   for(t1=NULL;*t;*t=t1) {
00318     CF_RW_RD(&((*t)->lock));
00319 
00320     /* we jumped to the next thread */
00321     if(t1) *p = (*t)->postings;
00322 
00323     /* count the posts :) */
00324     for(;*p && *anum < num;*p=(*p)->next,*anum += 1);
00325 
00326     /* found? */
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   /* hu? what happened? Compiler bug? */
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] == '<') { /* article selection by message id; pointer will not be modified */
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 { /* article selection by number; modifies pointer! */
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           /* easy going ;) */
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             /* search for the date */
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 /* eof */

Generated on Sun Apr 25 16:37:39 2004 for Classic Forum by doxygen 1.3.5