Skeleton module for POP3 client
[citadel.git] / citadel / serv_extensions.c
1 /*
2  * $Id$
3  *
4  * Citadel Dynamic Loading Module
5  * Written by Brian Costello <btx@calyx.net>
6  *
7  */
8
9 #include "sysdep.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <dirent.h>
15 #include <string.h>
16 #include <limits.h>
17 #include <ctype.h>
18 #include "citadel.h"
19 #include "server.h"
20 #include "serv_extensions.h"
21 #include "sysdep_decls.h"
22 #include "msgbase.h"
23 #include "tools.h"
24 #include "config.h"
25
26 #include "modules/crypto/serv_crypto.h" /* Needed until a universal crypto startup hook is implimented for CtdlStartTLS */
27
28 #ifndef HAVE_SNPRINTF
29 #include <stdarg.h>
30 #include "snprintf.h"
31 #endif
32
33 struct CleanupFunctionHook *CleanupHookTable = NULL;
34 struct SessionFunctionHook *SessionHookTable = NULL;
35 struct UserFunctionHook *UserHookTable = NULL;
36 struct XmsgFunctionHook *XmsgHookTable = NULL;
37 struct MessageFunctionHook *MessageHookTable = NULL;
38 struct NetprocFunctionHook *NetprocHookTable = NULL;
39 struct DeleteFunctionHook *DeleteHookTable = NULL;
40 struct ServiceFunctionHook *ServiceHookTable = NULL;
41 struct FixedOutputHook *FixedOutputTable = NULL;
42 struct RoomFunctionHook *RoomHookTable = NULL;
43 struct MaintenanceThreadHook *MaintenanceThreadHookTable = NULL;
44 struct SearchFunctionHook *SearchFunctionHookTable = NULL;
45
46 struct ProtoFunctionHook {
47         void (*handler) (char *cmdbuf);
48         char *cmd;
49         char *desc;
50         struct ProtoFunctionHook *next;
51 } *ProtoHookList = NULL;
52
53
54 #define ERR_PORT (1 << 1)
55
56
57 static char *portlist = NULL;
58 static size_t nSizPort = 0;
59
60 static char *errormessages = NULL;
61 size_t nSizErrmsg = 0;
62
63
64 long   DetailErrorFlags;
65
66 char *ErrSubject = "Startup Problems";
67 char *ErrGeneral = "Citadel had trouble on starting up. %s This means, citadel won't be the service provider for a specific service you configured it to.\n\n"
68 "If you don't want citadel to provide these services, turn them off in WebCit via %s%s\n\n%s\n\n"
69 "To make both ways actualy take place restart the citserver with \"sendcommand down\"\n\n"
70 "The errors returned by the system were:\n%s\n"
71 "You can recheck the above if you follow this faq item:\n"
72 "http://www.citadel.org/doku.php/faq:mastering_your_os:net#netstat";
73
74
75 char *ErrPortShort = "We couldn't bind all ports you configured to be provided by citadel server.";
76 char *ErrPortWhere = "Admin->System Preferences->Network.\n\nThe failed ports and sockets are: ";
77 char *ErrPortHint = "If you want citadel to provide you with that functionality, "
78 "check the output of \"netstat -lnp\" on linux Servers or \"netstat -na\" on *BSD"
79 " and stop the programm, that binds these ports. You should eventually remove "
80 " their initscripts in /etc/init.d so that you won't get this trouble once more.\n";
81
82
83 void LogPrintMessages(long err)
84 {
85         char *List, *DetailList, *Short, *Where, *Hint, *Message; 
86         int n = nSizPort + nSizErrmsg + 5;
87
88         Message = (char*) malloc(n * SIZ);
89
90         switch (err)
91         {
92         case ERR_PORT:
93                 Short = ErrPortShort;
94                 Where = ErrPortWhere;
95                 Hint  = ErrPortHint;
96                 List  = portlist;
97                 DetailList = errormessages;
98                 break;
99         default:
100                 Short = "";
101                 Where = "";
102                 Hint  = "";
103                 List  = "";
104                 DetailList = "";
105         }
106
107
108         snprintf(Message, n * SIZ, ErrGeneral, Short, Where, List, Hint, DetailList);
109
110         lprintf(0,Message);
111         lprintf(0,ErrSubject);
112         quickie_message("Citadel", NULL, NULL, AIDEROOM, Message, FMT_FIXED, ErrSubject);
113         if (errormessages!=NULL) free (errormessages);
114         errormessages = NULL;
115         if (portlist!=NULL) free (portlist);
116         portlist = NULL;
117         free(Message);
118 }
119
120
121
122 void AppendString(char **target, char *append, size_t *len, size_t rate)
123 {
124         size_t oLen = 0;
125         long AddLen;
126         long RelPtr = 0;
127
128         AddLen = strlen(append);
129
130         if (*len == 0)
131         {
132                 *len = rate;
133
134                 *target = (char*)malloc (*len * SIZ);
135         }
136         else 
137         {
138                 oLen = strlen(*target);
139                 RelPtr = strlen(*target);
140                 if (oLen + AddLen + 2 > *len * SIZ)
141                 {
142                         char *Buff = *target;
143                         size_t NewSiz = *len + 10;
144                         *target = malloc (NewSiz * SIZ);
145                         memcpy (*target, Buff, NewSiz * SIZ);
146                         *len = NewSiz;
147                 }
148         }
149         memcpy (*target + oLen, append, AddLen);
150         (*target)[oLen + AddLen + 1] = '\n';
151         (*target)[oLen + AddLen + 2] = '\0';
152 }
153
154 void AddPortError(char *Port, char *ErrorMessage)
155 {
156         char *pos;
157         long len;
158
159         DetailErrorFlags |= ERR_PORT;
160
161         AppendString(&errormessages, ErrorMessage, &nSizErrmsg, 10);
162         AppendString(&portlist, Port, &nSizPort, 2);
163
164         pos = strchr (portlist, ':');
165         if (pos != NULL) *pos = ';';
166         
167         len = strlen (errormessages);
168         if (nSizErrmsg * SIZ > len + 3)
169         {
170                 errormessages[len] = ';';
171                 errormessages[len+1] = ' ';
172                 errormessages[len+2] = '\0';
173         }       
174 }
175
176
177 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
178 {
179         struct ProtoFunctionHook *p;
180
181         p = (struct ProtoFunctionHook *)
182                 malloc(sizeof(struct ProtoFunctionHook));
183
184         if (p == NULL) {
185                 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
186                 exit(EXIT_FAILURE);
187         }
188         p->handler = handler;
189         p->cmd = cmd;
190         p->desc = desc;
191         p->next = ProtoHookList;
192         ProtoHookList = p;
193         lprintf(CTDL_INFO, "Registered server command %s (%s)\n", cmd, desc);
194 }
195
196
197 void CtdlUnregisterProtoHook(void (*handler) (char *), char *cmd)
198 {
199         struct ProtoFunctionHook *cur = NULL;
200         struct ProtoFunctionHook *p = NULL;
201         struct ProtoFunctionHook *lastcur = NULL;
202
203         for (cur = ProtoHookList; 
204              cur != NULL; 
205              cur = (cur != NULL)? cur->next: NULL) {
206                 /* This will also remove duplicates if any */
207                 while (cur != NULL &&
208                                 handler == cur->handler &&
209                                 !strcmp(cmd, cur->cmd)) {
210                         lprintf(CTDL_INFO, "Unregistered server command %s (%s)\n",
211                                         cmd, cur->desc);
212                         p = cur->next;
213                         if (cur == ProtoHookList) {
214                                 ProtoHookList = p;
215                         }
216                         else if (lastcur != NULL)
217                         {
218                                 lastcur->next = p;
219                         }
220                         free(cur);
221                         cur = p;
222                 }
223                 lastcur = cur;
224         }
225 }
226
227 void CtdlDestroyProtoHooks(void)
228 {
229         struct ProtoFunctionHook *cur, *p;
230
231         cur = ProtoHookList; 
232         while (cur != NULL)
233         {
234                 lprintf(CTDL_INFO, "Destroyed server command %s (%s)\n",
235                         cur->cmd, cur->desc);
236                 p = cur->next;
237                 free(cur);
238                 cur = p;
239         }
240         ProtoHookList = NULL;
241 }
242
243
244 int DLoader_Exec_Cmd(char *cmdbuf)
245 {
246         struct ProtoFunctionHook *p;
247
248         for (p = ProtoHookList; p; p = p->next) {
249                 if (!strncasecmp(cmdbuf, p->cmd, 4)) {
250                         p->handler(&cmdbuf[5]);
251                         return 1;
252                 }
253         }
254         return 0;
255 }
256
257
258 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
259 {
260
261         struct CleanupFunctionHook *newfcn;
262
263         newfcn = (struct CleanupFunctionHook *)
264             malloc(sizeof(struct CleanupFunctionHook));
265         newfcn->next = CleanupHookTable;
266         newfcn->h_function_pointer = fcn_ptr;
267         CleanupHookTable = newfcn;
268
269         lprintf(CTDL_INFO, "Registered a new cleanup function\n");
270 }
271
272
273 void CtdlUnregisterCleanupHook(void (*fcn_ptr) (void))
274 {
275         struct CleanupFunctionHook *cur, *p;
276
277         for (cur = CleanupHookTable; cur != NULL; cur = cur->next) {
278                 /* This will also remove duplicates if any */
279                 while (cur != NULL &&
280                                 fcn_ptr == cur->h_function_pointer) {
281                         lprintf(CTDL_INFO, "Unregistered cleanup function\n");
282                         p = cur->next;
283                         if (cur == CleanupHookTable) {
284                                 CleanupHookTable = p;
285                         }
286                         free(cur);
287                         cur = p;
288                 }
289         }
290 }
291
292 void CtdlDestroyCleanupHooks(void)
293 {
294         struct CleanupFunctionHook *cur, *p;
295
296         cur = CleanupHookTable;
297         while (cur != NULL)
298         {
299                 lprintf(CTDL_INFO, "Destroyed cleanup function\n");
300                 p = cur->next;
301                 free(cur);
302                 cur = p;
303         }
304         CleanupHookTable = NULL;
305 }
306
307
308 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType)
309 {
310
311         struct SessionFunctionHook *newfcn;
312
313         newfcn = (struct SessionFunctionHook *)
314             malloc(sizeof(struct SessionFunctionHook));
315         newfcn->next = SessionHookTable;
316         newfcn->h_function_pointer = fcn_ptr;
317         newfcn->eventtype = EventType;
318         SessionHookTable = newfcn;
319
320         lprintf(CTDL_INFO, "Registered a new session function (type %d)\n",
321                 EventType);
322 }
323
324
325 void CtdlUnregisterSessionHook(void (*fcn_ptr) (void), int EventType)
326 {
327         struct SessionFunctionHook *cur, *p;
328
329         for (cur = SessionHookTable; cur != NULL; cur = cur->next) {
330                 /* This will also remove duplicates if any */
331                 while (cur != NULL &&
332                                 fcn_ptr == cur->h_function_pointer &&
333                                 EventType == cur->eventtype) {
334                         lprintf(CTDL_INFO, "Unregistered session function (type %d)\n",
335                                         EventType);
336                         p = cur->next;
337                         if (cur == SessionHookTable) {
338                                 SessionHookTable = p;
339                         }
340                         free(cur);
341                         cur = p;
342                 }
343         }
344 }
345
346 void CtdlDestroySessionHooks(void)
347 {
348         struct SessionFunctionHook *cur, *p;
349
350         cur = SessionHookTable;
351         while (cur != NULL)
352         {
353                 lprintf(CTDL_INFO, "Destroyed session function\n");
354                 p = cur->next;
355                 free(cur);
356                 cur = p;
357         }
358         SessionHookTable = NULL;
359 }
360
361
362 void CtdlRegisterUserHook(void (*fcn_ptr) (struct ctdluser *), int EventType)
363 {
364
365         struct UserFunctionHook *newfcn;
366
367         newfcn = (struct UserFunctionHook *)
368             malloc(sizeof(struct UserFunctionHook));
369         newfcn->next = UserHookTable;
370         newfcn->h_function_pointer = fcn_ptr;
371         newfcn->eventtype = EventType;
372         UserHookTable = newfcn;
373
374         lprintf(CTDL_INFO, "Registered a new user function (type %d)\n",
375                 EventType);
376 }
377
378
379 void CtdlUnregisterUserHook(void (*fcn_ptr) (struct ctdluser *), int EventType)
380 {
381         struct UserFunctionHook *cur, *p;
382
383         for (cur = UserHookTable; cur != NULL; cur = cur->next) {
384                 /* This will also remove duplicates if any */
385                 while (cur != NULL &&
386                                 fcn_ptr == cur->h_function_pointer &&
387                                 EventType == cur->eventtype) {
388                         lprintf(CTDL_INFO, "Unregistered user function (type %d)\n",
389                                         EventType);
390                         p = cur->next;
391                         if (cur == UserHookTable) {
392                                 UserHookTable = p;
393                         }
394                         free(cur);
395                         cur = p;
396                 }
397         }
398 }
399
400 void CtdlDestroyUserHooks(void)
401 {
402         struct UserFunctionHook *cur, *p;
403
404         cur = UserHookTable;
405         while (cur != NULL)
406         {
407                 lprintf(CTDL_INFO, "Destroyed user function \n");
408                 p = cur->next;
409                 free(cur);
410                 cur = p;
411         }
412         UserHookTable = NULL;
413 }
414
415
416 void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *),
417                                 int EventType)
418 {
419
420         struct MessageFunctionHook *newfcn;
421
422         newfcn = (struct MessageFunctionHook *)
423             malloc(sizeof(struct MessageFunctionHook));
424         newfcn->next = MessageHookTable;
425         newfcn->h_function_pointer = handler;
426         newfcn->eventtype = EventType;
427         MessageHookTable = newfcn;
428
429         lprintf(CTDL_INFO, "Registered a new message function (type %d)\n",
430                 EventType);
431 }
432
433
434 void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *),
435                 int EventType)
436 {
437         struct MessageFunctionHook *cur, *p;
438
439         for (cur = MessageHookTable; cur != NULL; cur = cur->next) {
440                 /* This will also remove duplicates if any */
441                 while (cur != NULL &&
442                                 handler == cur->h_function_pointer &&
443                                 EventType == cur->eventtype) {
444                         lprintf(CTDL_INFO, "Unregistered message function (type %d)\n",
445                                         EventType);
446                         p = cur->next;
447                         if (cur == MessageHookTable) {
448                                 MessageHookTable = p;
449                         }
450                         free(cur);
451                         cur = p;
452                 }
453         }
454 }
455
456 void CtdlDestroyMessageHook(void)
457 {
458         struct MessageFunctionHook *cur, *p;
459
460         cur = MessageHookTable; 
461         while (cur != NULL)
462         {
463                 lprintf(CTDL_INFO, "Destroyed message function \n");
464                 p = cur->next;
465                 free(cur);
466                 cur = p;
467         }
468         MessageHookTable = NULL;
469 }
470
471
472 void CtdlRegisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
473 {
474         struct RoomFunctionHook *newfcn;
475
476         newfcn = (struct RoomFunctionHook *)
477             malloc(sizeof(struct RoomFunctionHook));
478         newfcn->next = RoomHookTable;
479         newfcn->fcn_ptr = fcn_ptr;
480         RoomHookTable = newfcn;
481
482         lprintf(CTDL_INFO, "Registered a new room function\n");
483 }
484
485
486 void CtdlUnregisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
487 {
488         struct RoomFunctionHook *cur, *p;
489
490         for (cur = RoomHookTable; cur != NULL; cur = cur->next) {
491                 while (cur != NULL && fcn_ptr == cur->fcn_ptr) {
492                         lprintf(CTDL_INFO, "Unregistered room function\n");
493                         p = cur->next;
494                         if (cur == RoomHookTable) {
495                                 RoomHookTable = p;
496                         }
497                         free(cur);
498                         cur = p;
499                 }
500         }
501 }
502
503
504 void CtdlDestroyRoomHooks(void)
505 {
506         struct RoomFunctionHook *cur, *p;
507
508         cur = RoomHookTable;
509         while (cur != NULL)
510         {
511                 lprintf(CTDL_INFO, "Unregistered room function\n");
512                 p = cur->next;
513                 free(cur);
514                 cur = p;
515         }
516         RoomHookTable = NULL;
517 }
518
519 void CtdlRegisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
520 {
521         struct NetprocFunctionHook *newfcn;
522
523         newfcn = (struct NetprocFunctionHook *)
524             malloc(sizeof(struct NetprocFunctionHook));
525         newfcn->next = NetprocHookTable;
526         newfcn->h_function_pointer = handler;
527         NetprocHookTable = newfcn;
528
529         lprintf(CTDL_INFO, "Registered a new netproc function\n");
530 }
531
532
533 void CtdlUnregisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
534 {
535         struct NetprocFunctionHook *cur, *p;
536
537         for (cur = NetprocHookTable; cur != NULL; cur = cur->next) {
538                 /* This will also remove duplicates if any */
539                 while (cur != NULL &&
540                                 handler == cur->h_function_pointer ) {
541                         lprintf(CTDL_INFO, "Unregistered netproc function\n");
542                         p = cur->next;
543                         if (cur == NetprocHookTable) {
544                                 NetprocHookTable = p;
545                         }
546                         free(cur);
547                         cur = p;
548                 }
549         }
550 }
551
552 void CtdlDestroyNetprocHooks(void)
553 {
554         struct NetprocFunctionHook *cur, *p;
555
556         cur = NetprocHookTable;
557         while (cur != NULL)
558         {
559                 lprintf(CTDL_INFO, "Unregistered netproc function\n");
560                 p = cur->next;
561                 free(cur);
562                 cur = p;
563         }
564         NetprocHookTable = NULL;
565 }
566
567
568 void CtdlRegisterDeleteHook(void (*handler)(char *, long) )
569 {
570         struct DeleteFunctionHook *newfcn;
571
572         newfcn = (struct DeleteFunctionHook *)
573             malloc(sizeof(struct DeleteFunctionHook));
574         newfcn->next = DeleteHookTable;
575         newfcn->h_function_pointer = handler;
576         DeleteHookTable = newfcn;
577
578         lprintf(CTDL_INFO, "Registered a new netproc function\n");
579 }
580
581
582 void CtdlUnregisterDeleteHook(void (*handler)(char *, long) )
583 {
584         struct DeleteFunctionHook *cur, *p;
585
586         for (cur = DeleteHookTable; cur != NULL; cur = cur->next) {
587                 /* This will also remove duplicates if any */
588                 while (cur != NULL &&
589                                 handler == cur->h_function_pointer ) {
590                         lprintf(CTDL_INFO, "Unregistered netproc function\n");
591                         p = cur->next;
592                         if (cur == DeleteHookTable) {
593                                 DeleteHookTable = p;
594                         }
595                         free(cur);
596                         cur = p;
597                 }
598         }
599 }
600 void CtdlDestroyDeleteHooks(void)
601 {
602         struct DeleteFunctionHook *cur, *p;
603
604         cur = DeleteHookTable;
605         while (cur != NULL)
606         {
607                 lprintf(CTDL_INFO, "Destroyed netproc function\n");
608                 p = cur->next;
609                 free(cur);
610                 cur = p;                
611         }
612         DeleteHookTable = NULL;
613 }
614
615
616
617
618 void CtdlRegisterFixedOutputHook(char *content_type, void (*handler)(char *, int) )
619 {
620         struct FixedOutputHook *newfcn;
621
622         newfcn = (struct FixedOutputHook *)
623             malloc(sizeof(struct FixedOutputHook));
624         newfcn->next = FixedOutputTable;
625         newfcn->h_function_pointer = handler;
626         safestrncpy(newfcn->content_type, content_type, sizeof newfcn->content_type);
627         FixedOutputTable = newfcn;
628
629         lprintf(CTDL_INFO, "Registered a new fixed output function for %s\n", newfcn->content_type);
630 }
631
632
633 void CtdlUnregisterFixedOutputHook(char *content_type)
634 {
635         struct FixedOutputHook *cur, *p;
636
637         for (cur = FixedOutputTable; cur != NULL; cur = cur->next) {
638                 /* This will also remove duplicates if any */
639                 while (cur != NULL && (!strcasecmp(content_type, cur->content_type))) {
640                         lprintf(CTDL_INFO, "Unregistered fixed output function for %s\n", content_type);
641                         p = cur->next;
642                         if (cur == FixedOutputTable) {
643                                 FixedOutputTable = p;
644                         }
645                         free(cur);
646                         cur = p;
647                 }
648         }
649 }
650
651 void CtdlDestroyFixedOutputHooks(void)
652 {
653         struct FixedOutputHook *cur, *p;
654
655         cur = FixedOutputTable; 
656         while (cur != NULL)
657         {
658                 lprintf(CTDL_INFO, "Destroyed fixed output function for %s\n", cur->content_type);
659                 p = cur->next;
660                 free(cur);
661                 cur = p;
662                 
663         }
664         FixedOutputTable = NULL;
665 }
666
667 /* returns nonzero if we found a hook and used it */
668 int PerformFixedOutputHooks(char *content_type, char *content, int content_length)
669 {
670         struct FixedOutputHook *fcn;
671
672         for (fcn = FixedOutputTable; fcn != NULL; fcn = fcn->next) {
673                 if (!strcasecmp(content_type, fcn->content_type)) {
674                         (*fcn->h_function_pointer) (content, content_length);
675                         return(1);
676                 }
677         }
678         return(0);
679 }
680
681
682
683
684
685 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *), int order)
686 {
687
688         struct XmsgFunctionHook *newfcn;
689
690         newfcn = (struct XmsgFunctionHook *)
691             malloc(sizeof(struct XmsgFunctionHook));
692         newfcn->next = XmsgHookTable;
693         newfcn->order = order;
694         newfcn->h_function_pointer = fcn_ptr;
695         XmsgHookTable = newfcn;
696         lprintf(CTDL_INFO, "Registered a new x-msg function (priority %d)\n", order);
697 }
698
699
700 void CtdlUnregisterXmsgHook(int (*fcn_ptr) (char *, char *, char *), int order)
701 {
702         struct XmsgFunctionHook *cur, *p;
703
704         for (cur = XmsgHookTable; cur != NULL; cur = cur->next) {
705                 /* This will also remove duplicates if any */
706                 while (cur != NULL &&
707                                 fcn_ptr == cur->h_function_pointer &&
708                                 order == cur->order) {
709                         lprintf(CTDL_INFO, "Unregistered x-msg function "
710                                         "(priority %d)\n", order);
711                         p = cur->next;
712                         if (cur == XmsgHookTable) {
713                                 XmsgHookTable = p;
714                         }
715                         free(cur);
716                         cur = p;
717                 }
718         }
719 }
720
721 void CtdlDestroyXmsgHooks(void)
722 {
723         struct XmsgFunctionHook *cur, *p;
724
725         cur = XmsgHookTable;
726         while (cur != NULL)
727         {
728                 lprintf(CTDL_INFO, "Destroyed x-msg function "
729                         "(priority %d)\n", cur->order);
730                 p = cur->next;
731                         
732                 free(cur);
733                 cur = p;
734         }
735         XmsgHookTable = NULL;
736 }
737
738
739 void CtdlRegisterServiceHook(int tcp_port,
740                              char *sockpath,
741                              void (*h_greeting_function) (void),
742                              void (*h_command_function) (void),
743                              void (*h_async_function) (void),
744                              const char *ServiceName)
745 {
746         struct ServiceFunctionHook *newfcn;
747         char *message;
748         char *error;
749
750         error = NULL;
751         newfcn = (struct ServiceFunctionHook *)
752             malloc(sizeof(struct ServiceFunctionHook));
753         message = (char*) malloc (SIZ);
754         
755         newfcn->next = ServiceHookTable;
756         newfcn->tcp_port = tcp_port;
757         newfcn->sockpath = sockpath;
758         newfcn->h_greeting_function = h_greeting_function;
759         newfcn->h_command_function = h_command_function;
760         newfcn->h_async_function = h_async_function;
761         newfcn->ServiceName = ServiceName;
762
763         if (sockpath != NULL) {
764                 newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions, &error);
765                 snprintf(message, SIZ, "Unix domain socket '%s': ", sockpath);
766         }
767         else if (tcp_port <= 0) {       /* port -1 to disable */
768                 lprintf(CTDL_INFO, "Service %s has been manually disabled, skipping\n", ServiceName);
769                 free (message);
770                 free(newfcn);
771                 return;
772         }
773         else {
774                 newfcn->msock = ig_tcp_server(config.c_ip_addr,
775                                               tcp_port,
776                                               config.c_maxsessions, 
777                                               &error);
778                 snprintf(message, SIZ, "TCP port %s:%d: (%s) ", 
779                          config.c_ip_addr, tcp_port, ServiceName);
780         }
781
782         if (newfcn->msock > 0) {
783                 ServiceHookTable = newfcn;
784                 strcat(message, "registered.");
785                 lprintf(CTDL_INFO, "%s\n", message);
786         }
787         else {
788                 AddPortError(message, error);
789                 strcat(message, "FAILED.");
790                 lprintf(CTDL_CRIT, "%s\n", message);
791                 free(error);
792                 free(newfcn);
793         }
794         free(message);
795 }
796
797
798 void CtdlUnregisterServiceHook(int tcp_port, char *sockpath,
799                         void (*h_greeting_function) (void),
800                         void (*h_command_function) (void),
801                         void (*h_async_function) (void)
802                         )
803 {
804         struct ServiceFunctionHook *cur, *p;
805
806         for (cur = ServiceHookTable; cur != NULL; cur = cur->next) {
807                 /* This will also remove duplicates if any */
808                 while (cur != NULL &&
809                                 !(sockpath && cur->sockpath &&
810                                         strcmp(sockpath, cur->sockpath)) &&
811                                 h_greeting_function == cur->h_greeting_function &&
812                                 h_command_function == cur->h_command_function &&
813                                 h_async_function == cur->h_async_function &&
814                                 tcp_port == cur->tcp_port) {
815                         close(cur->msock);
816                         if (sockpath) {
817                                 lprintf(CTDL_INFO, "Closed UNIX domain socket %s\n",
818                                                 sockpath);
819                         } else if (tcp_port) {
820                                 lprintf(CTDL_INFO, "Closed TCP port %d\n", tcp_port);
821                         } else {
822                                 lprintf(CTDL_INFO, "Unregistered unknown service\n");
823                         }
824                         p = cur->next;
825                         if (cur == ServiceHookTable) {
826                                 ServiceHookTable = p;
827                         }
828                         free(cur);
829                         cur = p;
830                 }
831         }
832 }
833
834 void CtdlDestroyServiceHook(void)
835 {
836         struct ServiceFunctionHook *cur, *p;
837
838         cur = ServiceHookTable;
839         while (cur != NULL)
840         {
841                 close(cur->msock);
842                 if (cur->sockpath) {
843                         lprintf(CTDL_INFO, "Closed UNIX domain socket %s\n",
844                                 cur->sockpath);
845                 } else if (cur->tcp_port) {
846                         lprintf(CTDL_INFO, "Closed TCP port %d\n", cur->tcp_port);
847                 } else {
848                         lprintf(CTDL_INFO, "Unregistered unknown service\n");
849                 }
850                 p = cur->next;
851                 free(cur);
852                 cur = p;
853         }
854         ServiceHookTable = NULL;
855 }
856
857 void CtdlRegisterSearchFuncHook(void (*fcn_ptr)(int *, long **, char *), char *name)
858 {
859         struct SearchFunctionHook *newfcn;
860
861         if (!name || !fcn_ptr) {
862                 return;
863         }
864         
865         newfcn = (struct SearchFunctionHook *)
866             malloc(sizeof(struct SearchFunctionHook));
867         newfcn->next = SearchFunctionHookTable;
868         newfcn->name = name;
869         newfcn->fcn_ptr = fcn_ptr;
870         SearchFunctionHookTable = newfcn;
871
872         lprintf(CTDL_INFO, "Registered a new search function (%s)\n", name);
873 }
874
875 void CtdlUnregisterSearchFuncHook(void (*fcn_ptr)(int *, long **, char *), char *name)
876 {
877         struct SearchFunctionHook *cur, *p;
878         
879         for (cur = SearchFunctionHookTable; cur != NULL; cur = cur->next) {
880                 while (fcn_ptr && (cur->fcn_ptr == fcn_ptr) && name && !strcmp(name, cur->name)) {
881                         lprintf(CTDL_INFO, "Unregistered search function(%s)\n", name);
882                         p = cur->next;
883                         if (cur == SearchFunctionHookTable) {
884                                 SearchFunctionHookTable = p;
885                         }
886                         free (cur);
887                         cur = p;
888                 }
889         }
890 }
891
892 void CtdlModuleDoSearch(int *num_msgs, long **search_msgs, char *search_string, char *func_name)
893 {
894         struct SearchFunctionHook *fcn = NULL;
895
896         for (fcn = SearchFunctionHookTable; fcn != NULL; fcn = fcn->next) {
897                 if (!func_name || !strcmp(func_name, fcn->name)) {
898                         (*fcn->fcn_ptr) (num_msgs, search_msgs, search_string);
899                         return;
900                 }
901         }
902         *num_msgs = 0;
903 }
904
905
906 void PerformSessionHooks(int EventType)
907 {
908         struct SessionFunctionHook *fcn = NULL;
909
910         for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
911                 if (fcn->eventtype == EventType) {
912                         (*fcn->h_function_pointer) ();
913                 }
914         }
915 }
916
917 void PerformUserHooks(struct ctdluser *usbuf, int EventType)
918 {
919         struct UserFunctionHook *fcn = NULL;
920
921         for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
922                 if (fcn->eventtype == EventType) {
923                         (*fcn->h_function_pointer) (usbuf);
924                 }
925         }
926 }
927
928 int PerformMessageHooks(struct CtdlMessage *msg, int EventType)
929 {
930         struct MessageFunctionHook *fcn = NULL;
931         int total_retval = 0;
932
933         /* Other code may elect to protect this message from server-side
934          * handlers; if this is the case, don't do anything.
935         lprintf(CTDL_DEBUG, "** Event type is %d, flags are %d\n",
936                 EventType, msg->cm_flags);
937          */
938         if (msg->cm_flags & CM_SKIP_HOOKS) {
939                 lprintf(CTDL_DEBUG, "Skipping hooks\n");
940                 return(0);
941         }
942
943         /* Otherwise, run all the hooks appropriate to this event type.
944          */
945         for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) {
946                 if (fcn->eventtype == EventType) {
947                         total_retval = total_retval +
948                                 (*fcn->h_function_pointer) (msg);
949                 }
950         }
951
952         /* Return the sum of the return codes from the hook functions.  If
953          * this is an EVT_BEFORESAVE event, a nonzero return code will cause
954          * the save operation to abort.
955          */
956         return total_retval;
957 }
958
959
960 int PerformRoomHooks(struct ctdlroom *target_room)
961 {
962         struct RoomFunctionHook *fcn;
963         int total_retval = 0;
964
965         lprintf(CTDL_DEBUG, "Performing room hooks for <%s>\n", target_room->QRname);
966
967         for (fcn = RoomHookTable; fcn != NULL; fcn = fcn->next) {
968                 total_retval = total_retval + (*fcn->fcn_ptr) (target_room);
969         }
970
971         /* Return the sum of the return codes from the hook functions.
972          */
973         return total_retval;
974 }
975
976
977 int PerformNetprocHooks(struct CtdlMessage *msg, char *target_room)
978 {
979         struct NetprocFunctionHook *fcn;
980         int total_retval = 0;
981
982         for (fcn = NetprocHookTable; fcn != NULL; fcn = fcn->next) {
983                 total_retval = total_retval +
984                         (*fcn->h_function_pointer) (msg, target_room);
985         }
986
987         /* Return the sum of the return codes from the hook functions.
988          * A nonzero return code will cause the message to *not* be imported.
989          */
990         return total_retval;
991 }
992
993
994 void PerformDeleteHooks(char *room, long msgnum)
995 {
996         struct DeleteFunctionHook *fcn;
997
998         for (fcn = DeleteHookTable; fcn != NULL; fcn = fcn->next) {
999                 (*fcn->h_function_pointer) (room, msgnum);
1000         }
1001 }
1002
1003
1004
1005
1006
1007 int PerformXmsgHooks(char *sender, char *recp, char *msg)
1008 {
1009         struct XmsgFunctionHook *fcn;
1010         int total_sent = 0;
1011         int p;
1012
1013         for (p=0; p<MAX_XMSG_PRI; ++p) {
1014                 for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
1015                         if (fcn->order == p) {
1016                                 total_sent +=
1017                                         (*fcn->h_function_pointer)
1018                                                 (sender, recp, msg);
1019                         }
1020                 }
1021                 /* Break out of the loop if a higher-priority function
1022                  * successfully delivered the message.  This prevents duplicate
1023                  * deliveries to local users simultaneously signed onto
1024                  * remote services.
1025                  */
1026                 if (total_sent) break;
1027         }
1028         return total_sent;
1029 }
1030
1031 void CtdlRegisterMaintenanceThread(char *name, void *(*thread_proc)(void *arg))
1032 {
1033         struct MaintenanceThreadHook *newfcn;
1034
1035         newfcn = (struct MaintenanceThreadHook *)
1036             malloc(sizeof(struct MaintenanceThreadHook));
1037         newfcn->name = name;
1038         newfcn->next = MaintenanceThreadHookTable;
1039         newfcn->fcn_ptr = thread_proc;
1040         MaintenanceThreadHookTable = newfcn;
1041
1042         lprintf(CTDL_INFO, "Registered a new maintenance thread function\n");
1043 }
1044
1045
1046 /*
1047  * Dirty hack until we impliment a hook mechanism for this
1048  */
1049 void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response)
1050 {
1051 #ifdef HAVE_OPENSSL
1052         CtdlStartTLS (ok_response, nosup_response, error_response);
1053 #endif
1054 }