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

serverlib.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 <stdlib.h>
00025 #include <stdio.h>
00026 #include <pthread.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <errno.h>
00030 
00031 #include <sys/types.h>
00032 
00033 /* socket includes */
00034 #include <sys/socket.h>
00035 #include <netdb.h>
00036 #include <unistd.h>
00037 #include <sys/un.h>
00038 
00039 #include <sys/stat.h>
00040 #include <sys/wait.h>
00041 #include <time.h>
00042 
00043 #include <gdome.h>
00044 
00045 #ifdef CF_SHARED_MEM
00046 #  ifdef MAX
00047 #    undef MAX /* max has been defined in the glib */
00048 #  endif
00049 #  ifdef MIN
00050 #    undef MIN /* min has been defined in the glib */
00051 #  endif
00052 
00053 #  include <sys/param.h>
00054 #  include <sys/ipc.h>
00055 #  include <sys/shm.h>
00056 #  include <sys/sem.h>
00057 #endif
00058 
00059 #ifdef CF_SHARED_MEM
00060 #  include "semaphores.h"
00061 #  include "shm_locking.h"
00062 #endif
00063 
00064 #include "cf_pthread.h"
00065 
00066 #include "hashlib.h"
00067 #include "utils.h"
00068 #include "configparser.h"
00069 #include "readline.h"
00070 #include "fo_server.h"
00071 #include "serverlib.h"
00072 #include "xml_handling.h"
00073 #include "charconvert.h"
00074 #include "archiver.h"
00075 
00076 /* }}} */
00077 
00078 /* {{{ cf_register_protocol_handler */
00079 int cf_register_protocol_handler(u_char *handler_hook,t_server_protocol_handler handler) {
00080   CF_RW_WR(&head.lock);
00081 
00082   if(head.protocol_handlers == NULL) {
00083     if((head.protocol_handlers = cf_hash_new(NULL)) == NULL) {
00084       cf_log(LOG_ERR,__FILE__,__LINE__,"cf_hash_new: %s\n",strerror(errno));
00085       exit(EXIT_FAILURE);
00086     }
00087   }
00088 
00089   if(cf_hash_set_static(head.protocol_handlers,handler_hook,strlen(handler_hook),handler) == 0) {
00090     cf_log(LOG_ERR,__FILE__,__LINE__,"cf_hash_set: %s\n",strerror(errno));
00091     return -1;
00092   }
00093 
00094   CF_RW_UN(&head.lock);
00095 
00096   return 0;
00097 }
00098 /* }}} */
00099 
00100 /* {{{ cf_register_thread */
00101 void cf_register_thread(t_thread *t) {
00102   u_char buff[50];
00103   size_t len;
00104 
00105   len = snprintf(buff,50,"t%lld",t->tid);
00106 
00107   CF_RW_WR(&head.threads_lock);
00108 
00109   if(!head.threads) head.threads = cf_hash_new(NULL);
00110 
00111   cf_hash_set(head.threads,buff,len,&t,sizeof(t));
00112 
00113   CF_RW_UN(&head.threads_lock);
00114 }
00115 /* }}} */
00116 
00117 /* {{{ cf_unregister_thread */
00118 void cf_unregister_thread(t_thread *t) {
00119   u_char buff[50];
00120   size_t len;
00121 
00122   len = snprintf(buff,50,"t%lld",t->tid);
00123 
00124   cf_log(LOG_DBG,__FILE__,__LINE__,"unregistering thread %lld...\n",t->tid);
00125 
00126   CF_RW_WR(&head.threads_lock);
00127 
00128   cf_hash_entry_delete(head.threads,buff,len);
00129 
00130   CF_RW_UN(&head.threads_lock);
00131 }
00132 /* }}} */
00133 
00134 /* {{{ cf_push_server
00135  * Returns:    -1 on failure, 0 on success
00136  * Parameters:
00137  *   - int sockfd             The server socket
00138  *   - struct sockaddr *addr  The address structure for the socket
00139  *   - int size               The size of the address structure
00140  *   - t_worker handler       The handler function for this server socket
00141  *
00142  * This function inserts a server socket into the server queque
00143  */
00144 int cf_push_server(int sockfd,struct sockaddr *addr,int size,t_worker handler) {
00145   t_server *cl;
00146 
00147   CF_LM(&head.server_lock);
00148 
00149   if(!head.servers) {
00150     head.servers         = fo_alloc(NULL,1,sizeof(t_server),FO_ALLOC_MALLOC);
00151     head.servers->worker = handler;
00152     head.servers->sock   = sockfd;
00153     head.servers->addr   = addr;
00154     head.servers->size   = size;
00155     head.servers->next   = NULL;
00156   }
00157   else {
00158     for(cl=head.servers;cl->next;cl=cl->next) {
00159       if(cl->sock == sockfd) {
00160         cf_log(LOG_ERR,__FILE__,__LINE__,"push_server: plugin tried to register server socket twicely (sock %d)\n",sockfd);
00161         CF_UM(&head.server_lock);
00162         return -1;
00163       }
00164     }
00165 
00166     if(cl->sock == sockfd) {
00167       cf_log(LOG_ERR,__FILE__,__LINE__,"push_server: plugin tried to register server socket twicely (sock %d)\n",sockfd);
00168       CF_UM(&head.server_lock);
00169       return -1;
00170     }
00171 
00172     cl->next         = fo_alloc(NULL,1,sizeof(t_server),FO_ALLOC_MALLOC);
00173     cl->next->sock   = sockfd;
00174     cl->next->worker = handler;
00175     cl->next->addr   = addr;
00176     cl->next->size   = size;
00177     cl->next->next   = NULL;
00178   }
00179 
00180 
00181   cf_log(LOG_STD,__FILE__,__LINE__,"push_server: registered server socket %d\n",sockfd);
00182   CF_UM(&head.server_lock);
00183 
00184   return 0;
00185 }
00186 /* }}} */
00187 
00188 /* {{{ cf_push_client
00189  * Returns:    -1 on failure, 0 on success
00190  * Parameters:
00191  *   - int connfd         The connection descriptor
00192  *   - t_worker handler   the handler function
00193  *
00194  * This function inserts a client into the client queque
00195  */
00196 int cf_push_client(int connfd,t_worker handler) {
00197   int status;
00198 
00199   /*
00200    * lock the queque
00201    */
00202   CF_LM(&head.clients.lock);
00203 
00204   /*
00205    * check if there are enough workers; we say, there have to be 3 clients per worker
00206    * but not more than MAX_WORKERS_NUM workers
00207    */
00208   while(head.clients.workers <= 0 || (head.clients.clientnum / head.clients.workers >= 3 && head.clients.workers <= MAX_WORKERS_NUM)) {
00209     /* create workers if there are not enough */
00210     if((status = pthread_create(&head.workers[head.clients.workers],NULL,cf_worker,NULL)) != 0) {
00211       cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_create: %s\n",strerror(status));
00212       RUN = 0;
00213       return -1;
00214     }
00215 
00216     cf_log(LOG_STD,__FILE__,__LINE__,"created worker %d now!\n",++head.clients.workers);
00217   }
00218 
00219 
00220   /* is there very high traffic? */
00221   if(head.clients.clientnum > MAX_CLIENT_NUM) {
00222     CF_UM(&head.clients.lock);
00223 
00224     cf_log(LOG_STD,__FILE__,__LINE__,"handling request directly...\n");
00225     handler(connfd);
00226   }
00227   else {
00228     /* insert the client into the queque */
00229     if(!head.clients.last) {
00230       head.clients.last         = head.clients.clients = fo_alloc(NULL,1,sizeof(t_client),FO_ALLOC_CALLOC);
00231       head.clients.last->sock   = connfd;
00232       head.clients.last->worker = handler;
00233       head.clients.last->next   = NULL;
00234     }
00235     else {
00236       head.clients.last->next         = fo_alloc(NULL,1,sizeof(t_client),FO_ALLOC_MALLOC);
00237       head.clients.last->next->sock   = connfd;
00238       head.clients.last->next->worker = handler;
00239       head.clients.last->next->next   = NULL;
00240       head.clients.last               = head.clients.last->next;
00241     }
00242 
00243     head.clients.clientnum++;
00244 
00245     CF_UM(&head.clients.lock);
00246 
00247     /* lock the conditional */
00248     CF_LM(&head.clients.cond_lock);
00249 
00250     /* wake up workers */
00251     pthread_cond_signal(&head.clients.cond);
00252 
00253     /* unlock conditional */
00254     CF_UM(&head.clients.cond_lock);
00255 
00256     CF_LM(&head.clients.lock);
00257 
00258     /* check for priority settings */
00259     if(head.clients.clientnum > CLIENT_PRIORITY_NUM) {
00260       CF_UM(&head.clients.lock);
00261 
00262       cf_log(LOG_STD,__FILE__,__LINE__,"yielding server thread...\n");
00263       pthread_yield();
00264     }
00265     else {
00266       CF_UM(&head.clients.lock);
00267     }
00268   }
00269 
00270   return 0;
00271 }
00272 /* }}} */
00273 
00274 /* {{{ cf_log
00275  * Returns: nothing
00276  * Parameters:
00277  *   - int mode            the mode to log (LOG_ERR or LOG_STD)
00278  *   - int line            the line number (0 if no number is given)
00279  *   - const u_char *format the format
00280  *   - ...                 the format args
00281  *
00282  * This function writes log entries to file
00283  *
00284  */
00285 void cf_log(int mode,const u_char *file,int line,const u_char *format,...) {
00286   u_char str[300];
00287   int status;
00288   t_name_value *v;
00289   time_t t;
00290   struct tm *tm;
00291   int sz;
00292   va_list ap;
00293   register u_char *ptr,*ptr1;
00294 
00295 #ifndef DEBUG
00296   if(mode == LOG_DBG) return;
00297 #endif
00298 
00299   for(ptr1=ptr=(u_char *)file;*ptr;ptr++) {
00300     if(*ptr == '/') ptr1 = ptr + 1;
00301   }
00302 
00303   t  = time(NULL);
00304   tm = localtime(&t);
00305 
00306   if((status = pthread_mutex_lock(&head.log_lock)) != 0) {
00307     fprintf(stderr,"pthread_mutex_lock: %s\n",strerror(status));
00308     return;
00309   }
00310 
00311   if(!head.std) {
00312     v = cfg_get_value(&fo_server_conf,"StdLog");
00313     head.std = fopen(v->values[0],"a");
00314   }
00315   if(!head.err) {
00316     v = cfg_get_value(&fo_server_conf,"ErrorLog");
00317     head.err = fopen(v->values[0],"a");
00318   }
00319 
00320   sz = snprintf(str,300,"[%4d-%02d-%02d %02d:%02d:%02d]:%s:%d ",tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,ptr1,line);
00321 
00322   va_start(ap, format);
00323   if(mode == LOG_ERR) {
00324     fwrite(str,sz,1,head.err);
00325     vfprintf(head.err,format,ap);
00326     fflush(head.err);
00327 
00328     #ifdef DEBUG
00329     fwrite(str,sz,1,stderr);
00330     vfprintf(stderr,format,ap);
00331     #endif
00332   }
00333   else if(mode == LOG_STD) {
00334     fwrite(str,sz,1,head.std);
00335     vfprintf(head.std,format,ap);
00336 
00337     /*
00338      * we want fflush() only if debugging is enabled
00339      * if not, we want to avoid system calls so fflush()
00340      * is silly and buffering is ok (stdlog is not critical,
00341      * stdlog contains only non-critical infos)
00342      */
00343     #ifdef DEBUG
00344     fflush(head.std);
00345 
00346     fwrite(str,sz,1,stdout);
00347     vfprintf(stdout,format,ap);
00348     #endif
00349   }
00350   #ifdef DEBUG
00351   else {
00352     fwrite(str,sz,1,head.std);
00353     fwrite(str,sz,1,stdout);
00354     fwrite("DEBUG: ",7,1,head.std);
00355     fwrite("DEBUG: ",7,1,stdout);
00356     vfprintf(head.std,format,ap);
00357     vfprintf(stdout,format,ap);
00358     fflush(head.std);
00359     fflush(stdout);
00360   }
00361   #endif
00362   va_end(ap);
00363 
00364   pthread_mutex_unlock(&head.log_lock);
00365 }
00366 /* }}} */
00367 
00368 /* {{{ cf_set_us_up_the_socket
00369  * Returns: int  the socket
00370  * Parameters:
00371  *   - struct sockaddr_un *addr    the sockaddr unix object
00372  *
00373  * this functions sets up the socket
00374  *
00375  */
00376 int cf_set_us_up_the_socket(struct sockaddr_un *addr) {
00377   int sock;
00378   t_name_value *sockpath = cfg_get_value(&fo_default_conf,"SocketName");
00379 
00380   if(!sockpath) {
00381     cf_log(LOG_ERR,__FILE__,__LINE__,"could not find socket path!\n");
00382     RUN = 0;
00383     return -1;
00384   }
00385 
00386   sock = socket(AF_LOCAL,SOCK_STREAM,0);
00387 
00388   if(sock == -1) {
00389     cf_log(LOG_ERR,__FILE__,__LINE__,"socket: %s\n",sock,strerror(errno));
00390     RUN = 0;
00391     return -1;
00392   }
00393 
00394   unlink(sockpath->values[0]);
00395 
00396   memset(addr,0,sizeof(struct sockaddr_un));
00397   addr->sun_family = AF_LOCAL;
00398   (void)strncpy(addr->sun_path,sockpath->values[0],104);
00399 
00400   if(bind(sock,(struct sockaddr *)addr,sizeof(struct sockaddr_un)) < 0) {
00401     cf_log(LOG_ERR,__FILE__,__LINE__,"bind: %s\n",strerror(errno));
00402     RUN = 0;
00403     return -1;
00404   }
00405 
00406   if(listen(sock,LISTENQ) != 0) {
00407     cf_log(LOG_ERR,__FILE__,__LINE__,"listen: %s\n",strerror(errno));
00408     RUN = 0;
00409     return -1;
00410   }
00411 
00412   chmod(sockpath->values[0],S_IRWXU|S_IRWXG|S_IRWXO);
00413 
00414   return sock;
00415 }
00416 /* }}} */
00417 
00418 /* {{{ cf_worker
00419  * Returns: NULL
00420  * Parameters:
00421  *   - void *arg    will always be NULL
00422  *
00423  * this function is a worker
00424  *
00425  */
00426 void *cf_worker(void *arg) {
00427   t_client *client;
00428   struct timespec timeout;
00429   int retries = 0,status;
00430 
00431   while(RUN) {
00432     /*
00433      * First, we look, if there are already entries in the queque. Therefore
00434      * we have to lock it.
00435      */
00436     CF_LM(&head.clients.lock);
00437 
00438     while(!head.clients.clients && RUN) {
00439       /*  ok, no clients seem to exist in the queque. Lets wait for them. */
00440       CF_UM(&head.clients.lock);
00441 
00442       /* lock conditional */
00443       CF_LM(&head.clients.cond_lock);
00444 
00445       /* wait time for the server (we don't trust the server, he could tell us to wait until neverneverday :) */
00446       timeout.tv_sec  = time(NULL) + 5; /* we wait 5 seconds maximum */
00447       timeout.tv_nsec = 0;
00448 
00449       /* ok, lets go sleeping... */
00450       if((status = pthread_cond_timedwait(&head.clients.cond,&head.clients.cond_lock.mutex,&timeout)) != 0) {
00451         CF_UM(&head.clients.cond_lock);
00452 
00453         /* uh, oh, fucking error or timeout? */
00454         if(status != ETIMEDOUT)  {
00455           cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_cond_timedwait: %s. We're going to retry it...\n",strerror(status));
00456           retries++;
00457         }
00458         else {
00459           retries = 0;
00460         }
00461 
00462         CF_LM(&head.clients.lock);
00463 
00464         if(retries < 3) {
00465           continue;
00466         }
00467         else {
00468           cf_log(LOG_ERR,__FILE__,__LINE__,"Worker tried it three times, and he got three times an error. He goes down...\n");
00469           head.clients.workers--;
00470           CF_UM(&head.clients.lock);
00471           return NULL;
00472         }
00473       }
00474 
00475       /* Lock no longer needed */
00476       CF_UM(&head.clients.cond_lock);
00477 
00478       /* we got an regular signal. Lock the queque and look, what happened. */
00479       CF_LM(&head.clients.lock);
00480     }
00481 
00482     /* shall we still run? */
00483     if(RUN) {
00484       /* ah, there seems to be something in the queque */
00485       client = head.clients.clients;
00486 
00487       if(client) {
00488         head.clients.clients = client->next;
00489         head.clients.clientnum--;
00490 
00491         if(!head.clients.clients) head.clients.last = NULL;
00492 
00493         CF_UM(&head.clients.lock);
00494 
00495         if(client->worker) {
00496           client->worker(client->sock);
00497         }
00498         else {
00499           /* uups. No worker defined. Waste the client... */
00500           cf_log(LOG_ERR,__FILE__,__LINE__,"Wasting client?!\n");
00501           close(client->sock);
00502         }
00503 
00504         free(client);
00505       }
00506       else {
00507         /* hu? What's going on? */
00508         CF_UM(&head.clients.lock);
00509       }
00510     }
00511     else {
00512       CF_UM(&head.clients.lock);
00513     }
00514   }
00515 
00516   return NULL;
00517 }
00518 /* }}} */
00519 
00520 /* {{{ cf_tokenize */
00527 int cf_tokenize(u_char *line,u_char ***tokens) {
00528   int n = 0,reser = 5;
00529   register u_char *ptr,*prev;
00530 
00531   *tokens = malloc(5 * sizeof(u_char **));
00532   if(!*tokens) return 0;
00533 
00534   for(prev=ptr=line;*ptr;ptr++) {
00535     if(n >= reser) {
00536       reser += 5;
00537       *tokens = fo_alloc(*tokens,reser,sizeof(*tokens),FO_ALLOC_REALLOC);
00538     }
00539 
00540     if(isspace(*ptr) || *ptr == ':') {
00541       if(ptr - 1 == prev || ptr == prev) {
00542         prev = ptr;
00543         continue;
00544       }
00545 
00546       *ptr = 0;
00547       (*tokens)[n++] = memdup(prev,ptr-prev+1);
00548       prev = ptr+1;
00549     }
00550   }
00551 
00552   if(prev != ptr && prev-1 != ptr && *ptr) (*tokens)[n++] = memdup(prev,ptr-prev);
00553 
00554   return n;
00555 }
00556 /* }}} */
00557 
00558 /* {{{ cf_handle_request
00559  * Returns: NULL
00560  * Parameters:
00561  *   - void *arg    This argument will be converted to
00562  *                  integer. It is the connection socket.
00563  *
00564  * this function handles a connection
00565  *
00566  */
00567 void cf_handle_request(int sockfd) {
00568   int           shallRun = 1,i;
00569   rline_t      *tsd        = fo_alloc(NULL,1,sizeof(*tsd),FO_ALLOC_CALLOC);
00570   u_char *line  = NULL,**tokens;
00571   int   locked = 0,tnum = 0;
00572 
00573   while(shallRun) {
00574     line = readline(sockfd,tsd);
00575     cf_log(LOG_DBG,__FILE__,__LINE__,"%s",line?line:(u_char *)"(NULL)\n");
00576 
00577     if(line) {
00578       tnum = cf_tokenize(line,&tokens);
00579 
00580       if(tnum) {
00581         if(cf_strcmp(tokens[0],"QUIT") == 0) {
00582           if(tnum == 2) {
00583             if(cf_strcmp(tokens[1],"SERVER") == 0) {
00584               shallRun = 0;
00585               RUN      = 0;
00586 
00587               writen(sockfd,"200 Bye, bye\n",13);
00588             }
00589             else {
00590               writen(sockfd,"500 What do you mean?\n",22);
00591             }
00592           }
00593           else {
00594             shallRun = 0;
00595             writen(sockfd,"200 Bye, bye\n",13);
00596           }
00597         }
00598         else if(cf_strcmp(tokens[0],"ARCHIVE") == 0) {
00599           u_int64_t tid;
00600           u_char *ln = readline(sockfd,tsd);
00601 
00602           if(ln == NULL) {
00603             cf_log(LOG_ERR,__FILE__,__LINE__,"declined archivation because user name not present\n");
00604             writen(sockfd,"403 Access Denied\n",18);
00605           }
00606           if(tnum < 3) {
00607             writen(sockfd,"500 Sorry\n",10);
00608             cf_log(LOG_ERR,__FILE__,__LINE__,"Bad request\n");
00609           }
00610           else {
00611             tid      = strtoull(tokens[2]+2,NULL,10);
00612             cf_log(LOG_ERR,__FILE__,__LINE__,"archiving thread %lld by user %s",tid,ln);
00613 
00614             cf_archive_thread(sockfd,tid);
00615             cf_generate_cache(NULL);
00616           }
00617 
00618           if(ln) free(ln);
00619         }
00620         else if(cf_strcmp(tokens[0],"DELETE") == 0) {
00621           u_int64_t tid,mid;
00622           t_thread *t;
00623           t_posting *p;
00624           int lvl;
00625           u_char *ln = readline(sockfd,tsd);
00626 
00627           if(ln == NULL) {
00628             cf_log(LOG_ERR,__FILE__,__LINE__,"declined deletion because user name not present\n");
00629             writen(sockfd,"403 Access Denied\n",18);
00630           }
00631           else if(tnum != 3) {
00632             writen(sockfd,"501 Thread id or message id missing\n",36);
00633           }
00634           else {
00635             tid = strtoull(tokens[1]+2,NULL,10);
00636             mid = strtoull(tokens[2]+2,NULL,10);
00637 
00638             t = cf_get_thread(tid);
00639 
00640             if(!t) {
00641               writen(sockfd,"404 Thread Not Found\n",21);
00642               cf_log(LOG_ERR,__FILE__,__LINE__,"Thread not found\n");
00643             }
00644             else {
00645               p = cf_get_posting(t,mid);
00646 
00647               if(!p) {
00648                 writen(sockfd,"404 Message Not Found\n",22);
00649                 cf_log(LOG_ERR,__FILE__,__LINE__,"Message not found\n");
00650               }
00651               else {
00652                 cf_log(LOG_ERR,__FILE__,__LINE__,"Deleted posting %lld in thread %lld by user %s\n",tid,mid,ln);
00653 
00654                 CF_RW_WR(&t->lock);
00655 
00656                 lvl          = p->level;
00657                 p->invisible = 1;
00658 
00659                 for(p=p->next;p && p->level > lvl;p=p->next) {
00660                   p->invisible = 1;
00661                 }
00662 
00663                 writen(sockfd,"200 Ok\n",7);
00664 
00665                 CF_RW_UN(&t->lock);
00666 
00667                 /* we need new caches if a message has been deleted */
00668                 cf_generate_cache(NULL);
00669               }
00670             }
00671           }
00672 
00673           if(ln) free(ln);
00674         }
00675         else if(cf_strcmp(tokens[0],"UNDELETE") == 0) {
00676           u_int64_t tid,mid;
00677           t_thread *t;
00678           t_posting *p;
00679           int lvl;
00680           u_char *ln = readline(sockfd,tsd);
00681 
00682           if(ln == NULL) {
00683             cf_log(LOG_ERR,__FILE__,__LINE__,"declined undelete because user name not present\n");
00684             writen(sockfd,"403 Access Denied\n",18);
00685           }
00686           if(tnum < 3) {
00687             writen(sockfd,"501 Thread id or message id missing\n",36);
00688           }
00689           else {
00690             tid = strtoull(tokens[1]+2,NULL,10);
00691             mid = strtoull(tokens[2]+2,NULL,10);
00692 
00693             t = cf_get_thread(tid);
00694 
00695             if(!t) {
00696               writen(sockfd,"404 Thread Not Found\n",21);
00697               cf_log(LOG_ERR,__FILE__,__LINE__,"Thread not found\n");
00698             }
00699             else {
00700               p = cf_get_posting(t,mid);
00701               cf_log(LOG_ERR,__FILE__,__LINE__,"Undelete posting %lld in posting %lld by user %lld\n",tid,mid,ln);
00702 
00703               if(!p) {
00704                 writen(sockfd,"404 Message Not Found\n",22);
00705                 cf_log(LOG_ERR,__FILE__,__LINE__,"Message not found\n");
00706               }
00707               else {
00708                 CF_RW_WR(&t->lock);
00709 
00710                 lvl          = p->level;
00711                 p->invisible = 0;
00712 
00713                 for(p=p->next;p && p->level > lvl;p=p->next) {
00714                   p->invisible = 0;
00715                 }
00716 
00717                 writen(sockfd,"200 Ok\n",7);
00718 
00719                 CF_RW_UN(&t->lock);
00720 
00721                 /* we need new caches if a message has been undeleted */
00722                 cf_generate_cache(NULL);
00723               }
00724             }
00725           }
00726 
00727           if(ln) free(ln);
00728         }
00729         else if(cf_strcmp(line,"UNLOCK") == 0) {
00730           if(tnum == 2 && cf_strcmp(tokens[1],"FORUM") == 0) {
00731             CF_RW_WR(&head.lock);
00732             head.locked = 0;
00733             CF_RW_UN(&head.lock);
00734           }
00735           else {
00736             writen(sockfd,"500 What's up?\n",15);
00737           }
00738         }
00739         else { /* everything else may only be done when the forum is *not* locked */
00740           CF_RW_RD(&head.lock);
00741           locked = head.locked;
00742           CF_RW_UN(&head.lock);
00743 
00744           if(locked == 0) {
00745             if(cf_strcmp(tokens[0],"LOCK") == 0) {
00746               if(tnum == 2 && cf_strcmp(tokens[1],"FORUM") == 0) {
00747                 CF_RW_WR(&head.lock);
00748                 head.locked = 1;
00749                 CF_RW_UN(&head.lock);
00750               }
00751               else {
00752                 writen(sockfd,"500 What's up?\n",15);
00753               }
00754             }
00755             else {
00756               /* run handlers */
00757               t_server_protocol_handler handler;
00758               int ret;
00759 
00760               CF_RW_RD(&head.lock);
00761 
00762               if(head.protocol_handlers) {
00763                 CF_RW_UN(&head.lock);
00764 
00765                 handler = cf_hash_get(head.protocol_handlers,tokens[0],strlen(tokens[0]));
00766                 if(handler == NULL) {
00767                   writen(sockfd,"500 What's up?\n",15);
00768                 }
00769                 else {
00770                   ret = handler(sockfd,(const u_char **)tokens,tnum,tsd);
00771 
00772                   if(ret == FLT_DECLINE) {
00773                     writen(sockfd,"500 What's up?\n",15);
00774                   }
00775                 }
00776               }
00777               else {
00778                 writen(sockfd,"500 What's up?\n",15);
00779                 CF_RW_UN(&head.lock);
00780               }
00781             }
00782           }
00783         }
00784 
00785         free(line);
00786         line = NULL;
00787 
00788         for(i=0;i<tnum;i++) free(tokens[i]);
00789         free(tokens);
00790       }
00791       else {
00792         writen(sockfd,"500 What's up?\n",15);
00793       }
00794     }
00795     else {
00796       shallRun = 0; /* connection broke */
00797     }
00798   }
00799 
00800   if(line) free(line);
00801 
00802   free(tsd);
00803   close(sockfd);
00804 }
00805 /* }}} */
00806 
00807 /* {{{ cf_read_posting
00808  * Returns: nothing
00809  * Parameters:
00810  *   - t_posting *p  the posting structure
00811  *   - int sock      the socket of the connection
00812  *
00813  * This function reads a posting from a client
00814  *
00815  */
00816 int cf_read_posting(t_posting *p,int sock,rline_t *tsd) {
00817   u_char *line = NULL;
00818   unsigned long llen;
00819   p->user.ip = NULL;
00820 
00821   do {
00822     line = readline(sock,tsd);
00823 
00824     if(line) {
00825       llen = tsd->rl_len;
00826       line[llen-1] = '\0';
00827 
00828       cf_log(LOG_DBG,__FILE__,__LINE__,"read_posting: got line %s\n",line);
00829 
00830       if(cf_strncmp(line,"Unid:",5) == 0) {
00831         p->unid     = strdup(line+6);
00832         p->unid_len = llen - 7;
00833       }
00834       else if(cf_strncmp(line,"Author:",7) == 0) {
00835         p->user.name     = strdup(line+8);
00836         p->user.name_len = llen - 9;
00837       }
00838       else if(cf_strncmp(line,"EMail:",6) == 0) {
00839         p->user.email     = strdup(line+7);
00840         p->user.email_len = llen - 8;
00841       }
00842       else if(cf_strncmp(line,"Category:",9) == 0) {
00843         p->category     = strdup(line+10);
00844         p->category_len = llen - 11;
00845       }
00846       else if(cf_strncmp(line,"Subject:",8) == 0) {
00847         p->subject     = strdup(line+9);
00848         p->subject_len = llen - 10;
00849       }
00850       else if(cf_strncmp(line,"HomepageUrl:",12) == 0) {
00851         p->user.hp     = strdup(line+13);
00852         p->user.hp_len = llen - 14;
00853       }
00854       else if(cf_strncmp(line,"ImageUrl:",9) == 0) {
00855         p->user.img     = strdup(line+10);
00856         p->user.img_len = llen - 11;
00857       }
00858       else if(cf_strncmp(line,"Body:",5) == 0) {
00859         p->content     = strdup(line+6);
00860         p->content_len = llen - 7;
00861       }
00862       else if(cf_strncmp(line,"RemoteAddr:",11) == 0) {
00863         p->user.ip     = strdup(line+12);
00864         p->user.ip_len = llen - 13;
00865       }
00866       else {
00867         free(line);
00868         line = NULL;
00869       }
00870 
00871       if(line) free(line);
00872     }
00873     else {
00874       cf_log(LOG_ERR,__FILE__,__LINE__,"readline: %s\n",strerror(errno));
00875     }
00876   } while(line);
00877 
00878   p->date = time(NULL);
00879 
00880   if(!p->user.name || !p->user.ip || !p->unid) {
00881     writen(sock,"500 Sorry\n",10);
00882     return 0;
00883   }
00884 
00885   CF_RW_WR(&head.lock);
00886   p->mid  = ++head.mid;
00887   CF_RW_UN(&head.lock);
00888 
00889   return 1;
00890 }
00891 /* }}} */
00892 
00893 /* {{{ cf_send_posting
00894  * Returns: nothing
00895  * Parameters:
00896  *   - int sock    the socket of the connection
00897  *   - u_int64_t tid     the thread id
00898  *   - u_int64_t mid     the message id
00899  *
00900  * this function sends a posting/thread to the client
00901  *
00902  */
00903 void cf_send_posting(int sock,u_int64_t tid,u_int64_t mid,int invisible) {
00904   int n;
00905   u_char buff[500];
00906   t_thread *t = cf_get_thread(tid);
00907   t_posting *p;
00908   t_string bff;
00909   int first = 1;
00910 
00911   if(!t) {
00912     writen(sock,"404 Thread not found\n",21);
00913     return;
00914   }
00915 
00916   if(mid != 0) {
00917     p = cf_get_posting(t,mid);
00918 
00919     if(!p) {
00920       writen(sock,"404 Posting not found\n",22);
00921       return;
00922     }
00923   }
00924 
00925   str_init(&bff);
00926 
00927   str_chars_append(&bff,"200 Ok\n",7);
00928 
00929   CF_RW_RD(&t->lock);
00930 
00931   if(p) {
00932     if(p->invisible == 1 && !invisible) {
00933       writen(sock,"404 Posting not found\n",22);
00934       CF_RW_UN(&t->lock);
00935       return;
00936     }
00937   }
00938 
00939   p = t->postings;
00940   n = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
00941   str_chars_append(&bff,buff,n);
00942 
00943   for(;p;p=p->next) {
00944     if(p->invisible && !invisible) {
00945       for(;p && p->invisible;p=p->next);
00946       if(!p) break;
00947     }
00948 
00949     if(!first) {
00950       n = sprintf(buff,"MSG m%lld\n",p->mid);
00951       str_chars_append(&bff,buff,n);
00952     }
00953 
00954     first = 0;
00955 
00956     str_chars_append(&bff,"Author:",7);
00957     str_chars_append(&bff,p->user.name,p->user.name_len);
00958 
00959     if(p->user.email) {
00960       str_chars_append(&bff,"\nEMail:",7);
00961       str_chars_append(&bff,p->user.email,p->user.email_len);
00962     }
00963 
00964     if(p->user.hp) {
00965       str_chars_append(&bff,"\nHomepage:",10);
00966       str_chars_append(&bff,p->user.hp,p->user.hp_len);
00967     }
00968 
00969     if(p->user.img) {
00970       str_chars_append(&bff,"\nImage:",7);
00971       str_chars_append(&bff,p->user.img,p->user.img_len);
00972     }
00973 
00974     str_chars_append(&bff,"\nSubject:",9);
00975     str_chars_append(&bff,p->subject,p->subject_len);
00976 
00977     if(p->category) {
00978       str_chars_append(&bff,"\nCategory:",10);
00979       str_chars_append(&bff,p->category,p->category_len);
00980     }
00981 
00982     n = sprintf(buff,"\nDate:%ld\n",p->date);
00983     str_chars_append(&bff,buff,n);
00984 
00985     n = sprintf(buff,"Level:%d\n",p->level);
00986     str_chars_append(&bff,buff,n);
00987 
00988     n = sprintf(buff,"Visible:%d\n",p->invisible == 0);
00989     str_chars_append(&bff,buff,n);
00990 
00991     str_chars_append(&bff,"Content:",8);
00992     str_chars_append(&bff,p->content,p->content_len);
00993 
00994     str_char_append(&bff,'\n');
00995   }
00996 
00997   CF_RW_UN(&t->lock);
00998 
00999   str_char_append(&bff,'\n');
01000 
01001   writen(sock,bff.content,bff.len);
01002   free(bff.content);
01003 }
01004 /* }}} */
01005 
01006 /* {{{ cf_get_posting
01007  * Returns: t_posting *  the posting or NULL
01008  * Parameters:
01009  *   - t_thread *t       a pointer to the thread
01010  *   - u_int64_t mid           the message id
01011  *
01012  * this function searches for a posting in the thread
01013  *
01014  */
01015 t_posting *cf_get_posting(t_thread *t,u_int64_t mid) {
01016   t_posting *p;
01017 
01018   CF_RW_RD(&t->lock);
01019 
01020   for(p=t->postings;p && p->mid != mid;p=p->next);
01021 
01022   CF_RW_UN(&t->lock);
01023 
01024   return p;  /* this returns NULL or the posting */
01025 }
01026 /* }}} */
01027 
01028 /* {{{ cf_get_thread
01029  * Returns: t_thread *   a pointer to the thread
01030  * Parameters:
01031  *   - u_int64_t tid           the thread id
01032  *
01033  * this function searches for a thread in the tree
01034  *
01035  */
01036 t_thread *cf_get_thread(u_int64_t tid) {
01037   t_thread **t = NULL;
01038   u_char buff[50];
01039   size_t len;
01040 
01041   len = snprintf(buff,50,"t%lld",tid);
01042 
01043   CF_RW_RD(&head.threads_lock);
01044   if(head.threads) t = cf_hash_get(head.threads,buff,len);
01045   CF_RW_UN(&head.threads_lock);
01046 
01047   return t ? *t : NULL;
01048 }
01049 /* }}} */
01050 
01051 /* {{{ CF_SHARED_MEM */
01052 #ifdef CF_SHARED_MEM
01053 
01054 /* {{{ cf_shmdt */
01061 int cf_shmdt(void *ptr) {
01062   cf_log(LOG_DBG,__FILE__,__LINE__,"shmdt: detaching %ld\n",ptr);
01063   return shmdt(ptr);
01064 }
01065 /* }}} */
01066 
01067 /* {{{ cf_shmat */
01076 void *cf_shmat(int shmid,void *addr,int shmflag) {
01077   void *ptr = shmat(shmid,addr,shmflag);
01078 
01079   cf_log(LOG_DBG,__FILE__,__LINE__,"shmat: attatching segment %d (%ld)\n",shmid,ptr);
01080 
01081   return ptr;
01082 }
01083 /* }}} */
01084 
01085 void cf_generate_shared_memory() {
01086   t_mem_pool pool;
01087   t_thread *t,*t1;
01088   t_posting *p;
01089   t_name_value *v = cfg_get_value(&fo_default_conf,"SharedMemIds");
01090   u_int32_t val;
01091   time_t tm = time(NULL);
01092   unsigned short semval;
01093 
01094   mem_init(&pool);
01095 
01096   CF_RW_RD(&head.lock);
01097   t1 = t = head.thread;
01098   CF_RW_UN(&head.lock);
01099 
01100   /*
01101    *
01102    * CAUTION! Deep magic begins here!
01103    *
01104    */
01105 
01106   mem_append(&pool,&tm,sizeof(t));
01107 
01108   for(;t;t=t1) {
01109     CF_RW_RD(&t->lock);
01110 
01111     /* we only need thread id and postings */
01112     mem_append(&pool,&(t->tid),sizeof(t->tid));
01113     mem_append(&pool,&(t->posts),sizeof(t->posts));
01114 
01115     for(p=t->postings;p;p=p->next) {
01116       mem_append(&pool,&(p->mid),sizeof(p->mid));
01117 
01118       val = p->subject_len + 1;
01119       mem_append(&pool,&val,sizeof(val));
01120       mem_append(&pool,p->subject,val);
01121 
01122       val = p->category_len + 1;
01123       if(val > 1) {
01124         mem_append(&pool,&val,sizeof(val));
01125         mem_append(&pool,p->category,val);
01126       }
01127       else {
01128         val = 0;
01129         mem_append(&pool,&val,sizeof(val));
01130       }
01131 
01132       val = p->content_len + 1;
01133       mem_append(&pool,&val,sizeof(val));
01134       mem_append(&pool,p->content,val);
01135 
01136       mem_append(&pool,&(p->date),sizeof(p->date));
01137       mem_append(&pool,&(p->level),sizeof(p->level));
01138       mem_append(&pool,&(p->invisible),sizeof(p->invisible));
01139 
01140       val = p->user.name_len + 1;
01141       mem_append(&pool,&val,sizeof(val));
01142       mem_append(&pool,p->user.name,val);
01143 
01144       val = p->user.email_len + 1;
01145       if(val > 1) {
01146         mem_append(&pool,&val,sizeof(val));
01147         mem_append(&pool,p->user.email,val);
01148       }
01149       else {
01150         val = 0;
01151         mem_append(&pool,&val,sizeof(val));
01152       }
01153 
01154       val = p->user.hp_len + 1;
01155       if(val > 1) {
01156         mem_append(&pool,&val,sizeof(val));
01157         mem_append(&pool,p->user.hp,val);
01158       }
01159       else {
01160         val = 0;
01161         mem_append(&pool,&val,sizeof(val));
01162       }
01163 
01164       val = p->user.img_len + 1;
01165       if(val > 1) {
01166         mem_append(&pool,&val,sizeof(val));
01167         mem_append(&pool,p->user.img,val);
01168       }
01169       else {
01170         val = 0;
01171         mem_append(&pool,&val,sizeof(val));
01172       }
01173     }
01174 
01175     t1 = t->next;
01176     CF_RW_UN(&t->lock);
01177     t = t1;
01178   }
01179 
01180   /*
01181    *
01182    * Phew. Deep magic ends
01183    *
01184    */
01185 
01186 
01187   /* lets go surfin' */
01188   CF_LM(&head.shm_lock);
01189 
01190   if(cf_sem_getval(head.shm_sem,0,1,&semval) == -1) {
01191     cf_log(LOG_ERR,__FILE__,__LINE__,"cf_sem_getval: %s\n",strerror(errno));
01192     exit(-1);
01193   }
01194 
01195   /* semval contains now the number of the shared memory segment *not* used */
01196   if(semval != 0 && semval != 1) {
01197     cf_log(LOG_ERR,__FILE__,__LINE__,"hu? what happened? semval is %d\n",semval);
01198     semval = 0;
01199   }
01200 
01201   cf_log(LOG_DBG,__FILE__,__LINE__,"shm_ids[%d]: %ld\n",semval,head.shm_ids[semval]);
01202 
01203   /* does the segment already exists? */
01204   if(head.shm_ids[semval] != -1) {
01205     /* yeah, baby, yeah! */
01206 
01207     cf_log(LOG_DBG,__FILE__,__LINE__,"shm_ptrs[%d]: %ld\n",semval,head.shm_ptrs[semval]);
01208 
01209     /* oh behave! detach the memory */
01210     if(head.shm_ptrs[semval]) {
01211       if(cf_shmdt(head.shm_ptrs[semval]) != 0) {
01212         cf_log(LOG_ERR,__FILE__,__LINE__,"shmdt: %s (semval: %d)\n",strerror(errno),semval);
01213         CF_UM(&head.shm_lock);
01214         mem_cleanup(&pool);
01215         return;
01216       }
01217     }
01218 
01219     /* delete the segment */
01220     if(shmctl(head.shm_ids[semval],IPC_RMID,NULL) != 0) {
01221       cf_log(LOG_ERR,__FILE__,__LINE__,"shmctl: %s\n",strerror(errno));
01222       CF_UM(&head.shm_lock);
01223       mem_cleanup(&pool);
01224       return;
01225     }
01226   }
01227 
01228   if((head.shm_ids[semval] = shmget(atoi(v->values[semval]),pool.len,IPC_CREAT|CF_SHARED_MODE)) == -1) {
01229     cf_log(LOG_ERR,__FILE__,__LINE__,"shmget: %s\n",strerror(errno));
01230     exit(EXIT_FAILURE);
01231   }
01232 
01233   if((head.shm_ptrs[semval] = cf_shmat(head.shm_ids[semval],NULL,0)) == NULL) {
01234     cf_log(LOG_ERR,__FILE__,__LINE__,"shmat: %s\n",strerror(errno));
01235     exit(EXIT_FAILURE);
01236   }
01237 
01238   memcpy(head.shm_ptrs[semval],pool.content,pool.len);
01239 
01240   mem_cleanup(&pool);
01241 
01242   if(semval == 1) {
01243     CF_SEM_DOWN(head.shm_sem,0);
01244   }
01245   else {
01246     CF_SEM_UP(head.shm_sem,0);
01247   }
01248 
01249   CF_UM(&head.shm_lock);
01250 
01251   cf_log(LOG_DBG,__FILE__,__LINE__,"generated shared memory segment %d\n",semval);
01252 }
01253 
01254 #endif
01255 /* }}} */
01256 
01257 /* {{{ cf_generate_cache
01258  * Returns: NULL
01259  * Parameters:
01260  *   - void *arg    should always be NULL
01261  *
01262  * this function generates the two cache lists
01263  *
01264  */
01265 void *cf_generate_cache(void *arg) {
01266 #ifndef CF_SHARED_MEM
01267   t_string str1,str2;
01268 
01269   str_init(&str1);
01270   str_init(&str2);
01271 
01272   cf_generate_list(&str1,0);
01273   cf_generate_list(&str2,1);
01274 
01275   CF_RW_WR(&head.lock);
01276 
01277   if(head.cache_invisible.content) {
01278     free(head.cache_invisible.content);
01279   }
01280   if(head.cache_visible.content) {
01281     free(head.cache_visible.content);
01282   }
01283 
01284   head.cache_invisible.content = str2.content;
01285   head.cache_visible.content   = str1.content;
01286   head.cache_invisible.len     = str2.len;
01287   head.cache_visible.len       = str1.len;
01288 
01289   head.date_visible            = time(NULL);
01290   head.date_invisible          = time(NULL);
01291 
01292   head.fresh = 1;
01293 
01294   CF_RW_UN(&head.lock);
01295 #else
01296   cf_generate_shared_memory();
01297 #endif
01298 
01299   return NULL;
01300 }
01301 /* }}} */
01302 
01303 /* {{{ cf_generate_list
01304  * Returns: u_char *  the thread list
01305  * Parameters:
01306  *   - short del    defines if the invisible
01307  *                  messages should be shown or not
01308  *
01309  * this function generates a thread list
01310  *
01311  */
01312 void cf_generate_list(t_string *str,int del) {
01313   int n;
01314   u_char buff[500];
01315   t_thread *t,*t1;
01316 
01317   str_chars_append(str,"200 Ok\n",7);
01318 
01319   CF_RW_RD(&head.lock);
01320   t1 = head.thread;
01321   CF_RW_UN(&head.lock);
01322 
01323   while(t1) {
01324     int               first = 1;
01325     t_posting        *p;
01326 
01327     t = t1;
01328 
01329     CF_RW_RD(&t->lock);
01330 
01331     for(p = t->postings;p;p = p->next) {
01332       if(p->invisible && !del) {
01333         for(;p && p->invisible;p=p->next);
01334 
01335         if(!p) {
01336           break;
01337         }
01338       }
01339 
01340 
01341       /* thread/posting header */
01342       if(first) {
01343         first = 0;
01344         n     = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
01345       }
01346       else {
01347         n     = sprintf(buff,"MSG m%lld\n",p->mid);
01348       }
01349 
01350       str_chars_append(str,buff,n);
01351 
01352       /* author */
01353       str_chars_append(str,"Author:",7);
01354       str_chars_append(str,p->user.name,p->user.name_len);
01355 
01356       /* subject */
01357       str_chars_append(str,"\nSubject:",9);
01358       str_chars_append(str,p->subject,p->subject_len);
01359 
01360       /* category */
01361       if(p->category) {
01362         str_chars_append(str,"\nCategory:",10);
01363         str_chars_append(str,p->category,p->category_len);
01364       }
01365 
01366       /* date */
01367       n = sprintf(buff,"\nDate:%ld\n",p->date);
01368       str_chars_append(str,buff,n);
01369 
01370       /* level */
01371       n = sprintf(buff,"Level:%d\n",p->level);
01372       str_chars_append(str,buff,n);
01373 
01374       n = sprintf(buff,"Visible:%d\n",p->invisible == 0);
01375       str_chars_append(str,buff,n);
01376     }
01377 
01378     str_chars_append(str,"END\n",4);
01379 
01380     t1   = t->next;
01381     CF_RW_UN(&t->lock);
01382   }
01383 
01384   str_char_append(str,'\n');
01385 }
01386 /* }}} */
01387 
01388 /* {{{ cf_send_thread_list
01389  * Returns: nothing
01390  * Parameters:
01391  *   - int sockfd   the socket handle of
01392  *                  the connection
01393  *   - int del      a true-false switch. If
01394  *                  true, the list includes also
01395  *                  invisible threads
01396  *
01397  * this function handles a connection
01398  *
01399  */
01400 void cf_send_thread_list(int sockfd,int del) {
01401   int n;
01402   u_char buff[500];
01403   t_thread *t,*t1;
01404 
01405   CF_RW_RD(&head.lock);
01406   t = head.thread;
01407   CF_RW_UN(&head.lock);
01408 
01409   writen(sockfd,"200 Ok\n",7);
01410 
01411   while(t) {
01412     int               first = 1;
01413     t_posting        *p;
01414 
01415     CF_RW_RD(&t->lock);
01416 
01417     for(p = t->postings;p;p = p->next) {
01418       if(p->invisible && !del) {
01419         for(;p && p->invisible;p=p->next);
01420 
01421         if(!p) {
01422           break;
01423         }
01424       }
01425 
01426       /* thread/posting header */
01427       if(first) {
01428         first = 0;
01429         n     = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
01430       }
01431       else {
01432         n     = sprintf(buff,"MSG m%lld\n",p->mid);
01433       }
01434 
01435       if(writen(sockfd,buff,n) <= 0) {
01436         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01437         CF_RW_UN(&t->lock);
01438         return;
01439       }
01440 
01441       /* author */
01442       if(writen(sockfd,"Author:",7) <= 0) {
01443         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01444         CF_RW_UN(&t->lock);
01445         return;
01446       }
01447       if(writen(sockfd,p->user.name,p->user.name_len) <= 0) {
01448         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01449         CF_RW_UN(&t->lock);
01450         return;
01451       }
01452 
01453       /* subject */
01454       if(writen(sockfd,"\nSubject:",9) <= 0) {
01455         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01456         CF_RW_UN(&t->lock);
01457         return;
01458       }
01459       if(writen(sockfd,p->subject,p->subject_len) <= 0) {
01460         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01461         CF_RW_UN(&t->lock);
01462         return;
01463       }
01464 
01465       /* category */
01466       if(p->category) {
01467         if(writen(sockfd,"\nCategory:",10) <= 0) {
01468           cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01469           CF_RW_UN(&t->lock);
01470           return;
01471         }
01472         if(writen(sockfd,p->category,p->category_len) <= 0) {
01473           cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01474           CF_RW_UN(&t->lock);
01475           return;
01476         }
01477       }
01478 
01479       /* date */
01480       n = sprintf(buff,"\nDate:%ld\n",p->date);
01481       if(writen(sockfd,buff,n) <= 0) {
01482         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01483         CF_RW_UN(&t->lock);
01484         return;
01485       }
01486 
01487       /* level */
01488       n = sprintf(buff,"Level:%d\n",p->level);
01489       if(writen(sockfd,buff,n) <= 0) {
01490         cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01491         CF_RW_UN(&t->lock);
01492         return;
01493       }
01494     }
01495 
01496     writen(sockfd,"END\n",4);
01497 
01498     t1 = t->next;
01499     CF_RW_UN(&t->lock);
01500     t  = t1;
01501   }
01502 
01503   writen(sockfd,"\n",1);
01504 }
01505 /* }}} */
01506 
01507 /* eof */

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