TDAP: add facility to protect usetable entries from being deleted while still needed.
[citadel.git] / citadel / serv_extensions.c
1 /*
2  * Citadel Dynamic Loading Module
3  * Written by Brian Costello <btx@calyx.net>
4  *
5  * Copyright (c) 1987-2011 by the citadel.org team
6  *
7  * This program is open source software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License, version 3.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include "sysdep.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <dirent.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <ctype.h>
25 #include <syslog.h>
26 #include <libcitadel.h>
27 #include "citadel.h"
28 #include "server.h"
29 #include "serv_extensions.h"
30 #include "sysdep_decls.h"
31 #include "msgbase.h"
32 #include "config.h"
33
34 #include "modules/crypto/serv_crypto.h" /* Needed until a universal crypto startup hook is implimented for CtdlStartTLS */
35
36 #include "ctdl_module.h"
37
38
39 int DebugModules = 0;
40  
41 /*
42  * Structure defentitions for hook tables
43  */
44
45 typedef struct __LogDebugEntry {
46         CtdlDbgFunction F;
47         const char *Name;
48         long Len;
49         const int *LogP;
50 } LogDebugEntry;
51 HashList *LogDebugEntryTable = NULL;
52
53 typedef struct LogFunctionHook LogFunctionHook;
54 struct LogFunctionHook {
55         LogFunctionHook *next;
56         int loglevel;
57         void (*h_function_pointer) (char *);
58 };
59
60 LogFunctionHook *LogHookTable = NULL;
61
62 typedef struct FixedOutputHook FixedOutputHook;
63 struct FixedOutputHook {
64         FixedOutputHook *next;
65         char content_type[64];
66         void (*h_function_pointer) (char *, int);
67 };
68 FixedOutputHook *FixedOutputTable = NULL;
69
70
71
72 /*
73  * TDAPVetoHookFunctionHook extensions are used for any type of hook for which
74  * may prevent the autopurger to run for this specific data class.
75  * the function should at least LOG_INFO that it does so.
76  */
77 typedef struct TDAPVetoHookFunctionHook TDAPVetoHookFunctionHook;
78 struct TDAPVetoHookFunctionHook {
79         TDAPVetoHookFunctionHook *next;
80         int Priority;
81         int (*h_function_pointer) (StrBuf *);
82         int eventtype;
83 };
84 TDAPVetoHookFunctionHook *TDAPVetoHookTable = NULL;
85
86
87
88 /*
89  * SessionFunctionHook extensions are used for any type of hook for which
90  * the context in which it's being called (which is determined by the event
91  * type) will make it obvious for the hook function to know where to look for
92  * pertinent data.
93  */
94 typedef struct SessionFunctionHook SessionFunctionHook;
95 struct SessionFunctionHook {
96         SessionFunctionHook *next;
97         int Priority;
98         void (*h_function_pointer) (void);
99         int eventtype;
100 };
101 SessionFunctionHook *SessionHookTable = NULL;
102
103 /*
104  * UserFunctionHook extensions are used for any type of hook which implements
105  * an operation on a user or username (potentially) other than the one
106  * operating the current session.
107  */
108 typedef struct UserFunctionHook UserFunctionHook;
109 struct UserFunctionHook {
110         UserFunctionHook *next;
111         void (*h_function_pointer) (struct ctdluser *usbuf);
112         int eventtype;
113 };
114 UserFunctionHook *UserHookTable = NULL;
115
116 /*
117  * MessageFunctionHook extensions are used for hooks which implement handlers
118  * for various types of message operations (save, read, etc.)
119  */
120 typedef struct MessageFunctionHook MessageFunctionHook;
121 struct MessageFunctionHook {
122         MessageFunctionHook *next;
123         int (*h_function_pointer) (struct CtdlMessage *msg);
124         int eventtype;
125 };
126 MessageFunctionHook *MessageHookTable = NULL;
127
128
129 /*
130  * NetprocFunctionHook extensions are used for hooks which implement handlers
131  * for incoming network messages.
132  */
133 typedef struct NetprocFunctionHook NetprocFunctionHook;
134 struct NetprocFunctionHook {
135         NetprocFunctionHook *next;
136         int (*h_function_pointer) (struct CtdlMessage *msg, char *target_room);
137 };
138 NetprocFunctionHook *NetprocHookTable = NULL;
139
140
141 /*
142  * DeleteFunctionHook extensions are used for hooks which get called when a
143  * message is about to be deleted.
144  */
145 typedef struct DeleteFunctionHook DeleteFunctionHook;
146 struct DeleteFunctionHook {
147         DeleteFunctionHook *next;
148         void (*h_function_pointer) (char *target_room, long msgnum);
149 };
150 DeleteFunctionHook *DeleteHookTable = NULL;
151
152
153 /*
154  * ExpressMessageFunctionHook extensions are used for hooks which implement
155  * the sending of an instant message through various channels.  Any function
156  * registered should return the number of recipients to whom the message was
157  * successfully transmitted.
158  */
159 typedef struct XmsgFunctionHook XmsgFunctionHook;
160 struct XmsgFunctionHook {
161         XmsgFunctionHook *next;
162         int (*h_function_pointer) (char *, char *, char *, char *);
163         int order;
164 };
165 XmsgFunctionHook *XmsgHookTable = NULL;
166
167
168
169
170 /*
171  * RoomFunctionHook extensions are used for hooks which impliment room
172  * processing functions when new messages are added EG. SIEVE.
173  */
174 typedef struct RoomFunctionHook RoomFunctionHook;
175 struct RoomFunctionHook {
176         RoomFunctionHook *next;
177         int (*fcn_ptr) (struct ctdlroom *);
178 };
179 RoomFunctionHook *RoomHookTable = NULL;
180
181
182
183 typedef struct SearchFunctionHook SearchFunctionHook;
184 struct SearchFunctionHook {
185         SearchFunctionHook *next;
186         void (*fcn_ptr) (int *, long **, const char *);
187         char *name;
188 };
189 SearchFunctionHook *SearchFunctionHookTable = NULL;
190
191 CleanupFunctionHook *CleanupHookTable = NULL;
192 CleanupFunctionHook *EVCleanupHookTable = NULL;
193
194 ServiceFunctionHook *ServiceHookTable = NULL;
195
196 typedef struct ProtoFunctionHook ProtoFunctionHook;
197 struct ProtoFunctionHook {
198         void (*handler) (char *cmdbuf);
199         const char *cmd;
200         const char *desc;
201 };
202
203 HashList *ProtoHookList = NULL;
204
205
206 #define ERR_PORT (1 << 1)
207
208
209 static StrBuf *portlist = NULL;
210
211 static StrBuf *errormessages = NULL;
212
213
214 long   DetailErrorFlags;
215 ConstStr Empty = {HKEY("")};
216 char *ErrSubject = "Startup Problems";
217 ConstStr ErrGeneral[] = {
218         {HKEY("Citadel had trouble on starting up. ")},
219         {HKEY(" This means, citadel won't be the service provider for a specific service you configured it to.\n\n"
220               "If you don't want citadel to provide these services, turn them off in WebCit via: ")},
221         {HKEY("To make both ways actualy take place restart the citserver with \"sendcommand down\"\n\n"
222               "The errors returned by the system were:\n")},
223         {HKEY("You can recheck the above if you follow this faq item:\n"
224               "http://www.citadel.org/doku.php?id=faq:mastering_your_os:net#netstat")}
225 };
226
227 ConstStr ErrPortShort = { HKEY("We couldn't bind all ports you configured to be provided by citadel server.\n")};
228 ConstStr ErrPortWhere = { HKEY("\"Admin->System Preferences->Network\".\n\nThe failed ports and sockets are: ")};
229 ConstStr ErrPortHint  = { HKEY("If you want citadel to provide you with that functionality, "
230                                "check the output of \"netstat -lnp\" on linux Servers or \"netstat -na\" on *BSD"
231                                " and stop the program that binds these ports.\n You should eventually remove "
232                                " their initscripts in /etc/init.d so that you won't get this trouble once more.\n"
233                                " After that goto \"Administration -> Shutdown Citadel\" to make Citadel restart & retry to bind this port.\n")};
234
235
236 void LogPrintMessages(long err)
237 {
238         StrBuf *Message;
239         StrBuf *List, *DetailList;
240         ConstStr *Short, *Where, *Hint; 
241
242         
243         Message = NewStrBufPlain(NULL, 
244                                  StrLength(portlist) + StrLength(errormessages));
245         
246         DetailErrorFlags = DetailErrorFlags & ~err;
247
248         switch (err)
249         {
250         case ERR_PORT:
251                 Short = &ErrPortShort;
252                 Where = &ErrPortWhere;
253                 Hint  = &ErrPortHint;
254                 List  = portlist;
255                 DetailList = errormessages;
256                 break;
257         default:
258                 Short = &Empty;
259                 Where = &Empty;
260                 Hint  = &Empty;
261                 List  = NULL;
262                 DetailList = NULL;
263         }
264
265         StrBufAppendBufPlain(Message, CKEY(ErrGeneral[0]), 0);
266         StrBufAppendBufPlain(Message, CKEY(*Short), 0); 
267         StrBufAppendBufPlain(Message, CKEY(ErrGeneral[1]), 0);
268         StrBufAppendBufPlain(Message, CKEY(*Where), 0);
269         StrBufAppendBuf(Message, List, 0);
270         StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
271         StrBufAppendBufPlain(Message, CKEY(*Hint), 0);
272         StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
273         StrBufAppendBufPlain(Message, CKEY(ErrGeneral[2]), 0);
274         StrBufAppendBuf(Message, DetailList, 0);
275         StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
276         StrBufAppendBufPlain(Message, CKEY(ErrGeneral[3]), 0);
277
278         MOD_syslog(LOG_EMERG, "%s", ChrPtr(Message));
279         MOD_syslog(LOG_EMERG, "%s", ErrSubject);
280         quickie_message("Citadel", NULL, NULL, AIDEROOM, ChrPtr(Message), FMT_FIXED, ErrSubject);
281
282         FreeStrBuf(&Message);
283         FreeStrBuf(&List);
284         FreeStrBuf(&DetailList);
285 }
286
287
288 void AddPortError(char *Port, char *ErrorMessage)
289 {
290         long len;
291
292         DetailErrorFlags |= ERR_PORT;
293
294         len = StrLength(errormessages);
295         if (len > 0) StrBufAppendBufPlain(errormessages, HKEY("; "), 0);
296         else errormessages = NewStrBuf();
297         StrBufAppendBufPlain(errormessages, ErrorMessage, -1, 0);
298
299
300         len = StrLength(portlist);
301         if (len > 0) StrBufAppendBufPlain(portlist, HKEY(";"), 0);
302         else portlist = NewStrBuf();
303         StrBufAppendBufPlain(portlist, Port, -1, 0);
304 }
305
306
307 int DLoader_Exec_Cmd(char *cmdbuf)
308 {
309         void *vP;
310         ProtoFunctionHook *p;
311
312         if (GetHash(ProtoHookList, cmdbuf, 4, &vP) && (vP != NULL)) {
313                 p = (ProtoFunctionHook*) vP;
314                 p->handler(&cmdbuf[5]);
315                 return 1;
316         }
317         return 0;
318 }
319
320 long FourHash(const char *key, long length) 
321 {
322         int i;
323         int ret = 0;
324         const unsigned char *ptr = (const unsigned char*)key;
325
326         for (i = 0; i < 4; i++, ptr ++) 
327                 ret = (ret << 8) | 
328                         ( ((*ptr >= 'a') &&
329                            (*ptr <= 'z'))? 
330                           *ptr - 'a' + 'A': 
331                           *ptr);
332
333         return ret;
334 }
335
336 void CtdlRegisterDebugFlagHook(const char *Name, long Len, CtdlDbgFunction F, const int *LogP)
337 {
338         LogDebugEntry *E;
339         if (LogDebugEntryTable == NULL)
340                 LogDebugEntryTable = NewHash(1, NULL);
341         E = (LogDebugEntry*) malloc(sizeof(LogDebugEntry));
342         E->F = F;
343         E->Name = Name;
344         E->Len = Len;
345         E->LogP = LogP;
346         Put(LogDebugEntryTable, Name, Len, E, NULL);
347         
348 }
349 void CtdlSetDebugLogFacilities(const char **Str, long n)
350 {
351         StrBuf *Token = NULL;
352         StrBuf *Buf = NULL;
353         const char *ch;
354         int i;
355         int DoAll = 0;
356         void *vptr;
357
358         for (i=0; i < n; i++){
359                 if ((Str[i] != NULL) && !IsEmptyStr(Str[i])) {
360                         if (strcmp(Str[i], "all") == 0) {
361                                 DoAll = 1;
362                                 continue;
363                         }
364                         Buf = NewStrBufPlain(Str[i], -1);
365                         ch = NULL;
366                         if (Token == NULL)
367                                 Token = NewStrBufPlain(NULL, StrLength(Buf));
368                         while ((ch != StrBufNOTNULL) &&
369                                StrBufExtract_NextToken(Token, Buf, &ch, ',')) {
370                                 if (GetHash(LogDebugEntryTable, SKEY(Token), &vptr) && 
371                                     (vptr != NULL))
372                                 {
373                                         LogDebugEntry *E = (LogDebugEntry*)vptr;
374                                         E->F(1);
375                                 }
376                         }
377                 }
378                 FreeStrBuf(&Buf);
379         }
380         FreeStrBuf(&Token);
381         if (DoAll) {
382                 long HKLen;
383                 const char *ch;
384                 HashPos *Pos;
385
386                 Pos = GetNewHashPos(LogDebugEntryTable, 0);
387                 while (GetNextHashPos(LogDebugEntryTable, Pos, &HKLen, &ch, &vptr)) {
388                         LogDebugEntry *E = (LogDebugEntry*)vptr;
389                         E->F(1);
390                 }
391
392                 DeleteHashPos(&Pos);
393         }
394 }
395 void cmd_log_get(char *argbuf)
396 {
397         long HKLen;
398         const char *ch;
399         HashPos *Pos;
400         void *vptr;
401
402         if (CtdlAccessCheck(ac_aide)) return;
403
404         cprintf("%d Log modules enabled:\n", LISTING_FOLLOWS);
405
406         Pos = GetNewHashPos(LogDebugEntryTable, 0);
407
408         while (GetNextHashPos(LogDebugEntryTable, Pos, &HKLen, &ch, &vptr)) {
409                 LogDebugEntry *E = (LogDebugEntry*)vptr;
410                 cprintf("%s|%d\n", ch, *E->LogP);
411         }
412         
413         DeleteHashPos(&Pos);
414         cprintf("000\n");
415 }
416 void cmd_log_set(char *argbuf)
417 {
418         void *vptr;
419         int lset;
420         int wlen;
421         char which[SIZ] = "";
422
423         if (CtdlAccessCheck(ac_aide)) return;
424
425         wlen = extract_token(which, argbuf, 0, '|', sizeof(which));
426         if (wlen < 0) wlen = 0;
427         lset = extract_int(argbuf, 1);
428         if (lset != 0) lset = 1;
429         if (GetHash(LogDebugEntryTable, which, wlen, &vptr) && 
430             (vptr != NULL))
431         {
432                 LogDebugEntry *E = (LogDebugEntry*)vptr;
433                 E->F(lset);
434                 cprintf("%d %s|%d\n", CIT_OK, which, lset);
435         }
436         else {
437                 cprintf("%d Log setting %s not known\n", 
438                         ERROR, which);
439         }
440 }
441 void CtdlDestroyDebugTable(void)
442 {
443
444         DeleteHash(&LogDebugEntryTable);
445 }
446
447 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
448 {
449         ProtoFunctionHook *p;
450
451         if (ProtoHookList == NULL)
452                 ProtoHookList = NewHash (1, FourHash);
453
454
455         p = (ProtoFunctionHook *)
456                 malloc(sizeof(ProtoFunctionHook));
457
458         if (p == NULL) {
459                 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
460                 exit(EXIT_FAILURE);
461         }
462         p->handler = handler;
463         p->cmd = cmd;
464         p->desc = desc;
465
466         Put(ProtoHookList, cmd, 4, p, NULL);
467         MOD_syslog(LOG_DEBUG, "Registered server command %s (%s)\n", cmd, desc);
468 }
469
470 void CtdlDestroyProtoHooks(void)
471 {
472
473         DeleteHash(&ProtoHookList);
474 }
475
476
477 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
478 {
479
480         CleanupFunctionHook *newfcn;
481
482         newfcn = (CleanupFunctionHook *)
483             malloc(sizeof(CleanupFunctionHook));
484         newfcn->next = CleanupHookTable;
485         newfcn->h_function_pointer = fcn_ptr;
486         CleanupHookTable = newfcn;
487
488         MODM_syslog(LOG_DEBUG, "Registered a new cleanup function\n");
489 }
490
491
492 void CtdlUnregisterCleanupHook(void (*fcn_ptr) (void))
493 {
494         CleanupFunctionHook *cur, *p, *last;
495         last = NULL;
496         cur = CleanupHookTable;
497         while (cur != NULL)
498         {
499                 if (fcn_ptr == cur->h_function_pointer)
500                 {
501                         MODM_syslog(LOG_DEBUG, "Unregistered cleanup function\n");
502                         p = cur->next;
503
504                         free(cur);
505                         cur = NULL;
506
507                         if (last != NULL)
508                                 last->next = p;
509                         else 
510                                 CleanupHookTable = p;
511                         cur = p;
512                 }
513                 else {
514                         last = cur;
515                         cur = cur->next;
516                 }
517         }
518 }
519
520
521 void CtdlDestroyCleanupHooks(void)
522 {
523         CleanupFunctionHook *cur, *p;
524
525         cur = CleanupHookTable;
526         while (cur != NULL)
527         {
528                 MODM_syslog(LOG_DEBUG, "Destroyed cleanup function\n");
529                 p = cur->next;
530                 free(cur);
531                 cur = p;
532         }
533         CleanupHookTable = NULL;
534 }
535
536 void CtdlRegisterEVCleanupHook(void (*fcn_ptr) (void))
537 {
538
539         CleanupFunctionHook *newfcn;
540
541         newfcn = (CleanupFunctionHook *)
542             malloc(sizeof(CleanupFunctionHook));
543         newfcn->next = EVCleanupHookTable;
544         newfcn->h_function_pointer = fcn_ptr;
545         EVCleanupHookTable = newfcn;
546
547         MODM_syslog(LOG_DEBUG, "Registered a new cleanup function\n");
548 }
549
550
551 void CtdlUnregisterEVCleanupHook(void (*fcn_ptr) (void))
552 {
553         CleanupFunctionHook *cur, *p, *last;
554         last = NULL;
555         cur = EVCleanupHookTable;
556         while (cur != NULL)
557         {
558                 if (fcn_ptr == cur->h_function_pointer)
559                 {
560                         MODM_syslog(LOG_DEBUG, "Unregistered cleanup function\n");
561                         p = cur->next;
562
563                         free(cur);
564                         cur = NULL;
565
566                         if (last != NULL)
567                                 last->next = p;
568                         else 
569                                 EVCleanupHookTable = p;
570                         cur = p;
571                 }
572                 else {
573                         last = cur;
574                         cur = cur->next;
575                 }
576         }
577 }
578
579
580 void CtdlDestroyEVCleanupHooks(void)
581 {
582         CleanupFunctionHook *cur, *p;
583
584         cur = EVCleanupHookTable;
585         while (cur != NULL)
586         {
587                 MODM_syslog(LOG_DEBUG, "Destroyed cleanup function\n");
588                 p = cur->next;
589                 cur->h_function_pointer();
590                 free(cur);
591                 cur = p;
592         }
593         EVCleanupHookTable = NULL;
594 }
595
596 void CtdlRegisterTDAPVetoHook(int (*fcn_ptr) (StrBuf*), int EventType, int Priority)
597 {
598         TDAPVetoHookFunctionHook *newfcn;
599
600         newfcn = (TDAPVetoHookFunctionHook *)
601             malloc(sizeof(TDAPVetoHookFunctionHook));
602         newfcn->Priority = Priority;
603         newfcn->h_function_pointer = fcn_ptr;
604         newfcn->eventtype = EventType;
605
606         TDAPVetoHookFunctionHook **pfcn;
607         pfcn = &TDAPVetoHookTable;
608         while ((*pfcn != NULL) && 
609                ((*pfcn)->Priority < newfcn->Priority) &&
610                ((*pfcn)->next != NULL))
611                 pfcn = &(*pfcn)->next;
612                 
613         newfcn->next = *pfcn;
614         *pfcn = newfcn;
615         
616         MOD_syslog(LOG_DEBUG, "Registered a new TDAP Veto function (type %d Priority %d)\n",
617                    EventType, Priority);
618 }
619
620
621 void CtdlUnregisterTDAPVetoHook(int (*fcn_ptr) (StrBuf*), int EventType)
622 {
623         TDAPVetoHookFunctionHook *cur, *p, *last;
624         last = NULL;
625         cur = TDAPVetoHookTable;
626         while  (cur != NULL) {
627                 if ((fcn_ptr == cur->h_function_pointer) &&
628                     (EventType == cur->eventtype))
629                 {
630                         MOD_syslog(LOG_DEBUG, "Unregistered TDAP Veto function (type %d)\n",
631                                    EventType);
632                         p = cur->next;
633
634                         free(cur);
635                         cur = NULL;
636
637                         if (last != NULL)
638                                 last->next = p;
639                         else 
640                                 TDAPVetoHookTable = p;
641                         cur = p;
642                 }
643                 else {
644                         last = cur;
645                         cur = cur->next;
646                 }
647         }
648 }
649
650 void CtdlDestroyTDAPVetoHooks(void)
651 {
652         TDAPVetoHookFunctionHook *cur, *p;
653
654         cur = TDAPVetoHookTable;
655         while (cur != NULL)
656         {
657                 MODM_syslog(LOG_DEBUG, "Destroyed TDAP Veto function\n");
658                 p = cur->next;
659                 free(cur);
660                 cur = p;
661         }
662         TDAPVetoHookTable = NULL;
663 }
664
665
666 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType, int Priority)
667 {
668         SessionFunctionHook *newfcn;
669
670         newfcn = (SessionFunctionHook *)
671             malloc(sizeof(SessionFunctionHook));
672         newfcn->Priority = Priority;
673         newfcn->h_function_pointer = fcn_ptr;
674         newfcn->eventtype = EventType;
675
676         SessionFunctionHook **pfcn;
677         pfcn = &SessionHookTable;
678         while ((*pfcn != NULL) && 
679                ((*pfcn)->Priority < newfcn->Priority) &&
680                ((*pfcn)->next != NULL))
681                 pfcn = &(*pfcn)->next;
682                 
683         newfcn->next = *pfcn;
684         *pfcn = newfcn;
685         
686         MOD_syslog(LOG_DEBUG, "Registered a new session function (type %d Priority %d)\n",
687                    EventType, Priority);
688 }
689
690
691 void CtdlUnregisterSessionHook(void (*fcn_ptr) (void), int EventType)
692 {
693         SessionFunctionHook *cur, *p, *last;
694         last = NULL;
695         cur = SessionHookTable;
696         while  (cur != NULL) {
697                 if ((fcn_ptr == cur->h_function_pointer) &&
698                     (EventType == cur->eventtype))
699                 {
700                         MOD_syslog(LOG_DEBUG, "Unregistered session function (type %d)\n",
701                                    EventType);
702                         p = cur->next;
703
704                         free(cur);
705                         cur = NULL;
706
707                         if (last != NULL)
708                                 last->next = p;
709                         else 
710                                 SessionHookTable = p;
711                         cur = p;
712                 }
713                 else {
714                         last = cur;
715                         cur = cur->next;
716                 }
717         }
718 }
719
720 void CtdlDestroySessionHooks(void)
721 {
722         SessionFunctionHook *cur, *p;
723
724         cur = SessionHookTable;
725         while (cur != NULL)
726         {
727                 MODM_syslog(LOG_DEBUG, "Destroyed session function\n");
728                 p = cur->next;
729                 free(cur);
730                 cur = p;
731         }
732         SessionHookTable = NULL;
733 }
734
735
736 void CtdlRegisterUserHook(void (*fcn_ptr) (ctdluser *), int EventType)
737 {
738
739         UserFunctionHook *newfcn;
740
741         newfcn = (UserFunctionHook *)
742             malloc(sizeof(UserFunctionHook));
743         newfcn->next = UserHookTable;
744         newfcn->h_function_pointer = fcn_ptr;
745         newfcn->eventtype = EventType;
746         UserHookTable = newfcn;
747
748         MOD_syslog(LOG_DEBUG, "Registered a new user function (type %d)\n",
749                    EventType);
750 }
751
752
753 void CtdlUnregisterUserHook(void (*fcn_ptr) (struct ctdluser *), int EventType)
754 {
755         UserFunctionHook *cur, *p, *last;
756         last = NULL;
757         cur = UserHookTable;
758         while (cur != NULL) {
759                 if ((fcn_ptr == cur->h_function_pointer) &&
760                     (EventType == cur->eventtype))
761                 {
762                         MOD_syslog(LOG_DEBUG, "Unregistered user function (type %d)\n",
763                                    EventType);
764                         p = cur->next;
765
766                         free(cur);
767                         cur = NULL;
768
769                         if (last != NULL)
770                                 last->next = p;
771                         else 
772                                 UserHookTable = p;
773                         cur = p;
774                 }
775                 else {
776                         last = cur;
777                         cur = cur->next;
778                 }
779         }
780 }
781
782 void CtdlDestroyUserHooks(void)
783 {
784         UserFunctionHook *cur, *p;
785
786         cur = UserHookTable;
787         while (cur != NULL)
788         {
789                 MODM_syslog(LOG_DEBUG, "Destroyed user function \n");
790                 p = cur->next;
791                 free(cur);
792                 cur = p;
793         }
794         UserHookTable = NULL;
795 }
796
797
798 void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *),
799                                 int EventType)
800 {
801
802         MessageFunctionHook *newfcn;
803
804         newfcn = (MessageFunctionHook *)
805             malloc(sizeof(MessageFunctionHook));
806         newfcn->next = MessageHookTable;
807         newfcn->h_function_pointer = handler;
808         newfcn->eventtype = EventType;
809         MessageHookTable = newfcn;
810
811         MOD_syslog(LOG_DEBUG, "Registered a new message function (type %d)\n",
812                    EventType);
813 }
814
815
816 void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *),
817                 int EventType)
818 {
819         MessageFunctionHook *cur, *p, *last;
820         last = NULL;
821         cur = MessageHookTable;
822         while (cur != NULL) {
823                 if ((handler == cur->h_function_pointer) &&
824                     (EventType == cur->eventtype))
825                 {
826                         MOD_syslog(LOG_DEBUG, "Unregistered message function (type %d)\n",
827                                    EventType);
828                         p = cur->next;
829                         free(cur);
830                         cur = NULL;
831
832                         if (last != NULL)
833                                 last->next = p;
834                         else 
835                                 MessageHookTable = p;
836                         cur = p;
837                 }
838                 else {
839                         last = cur;
840                         cur = cur->next;
841                 }
842         }
843 }
844
845 void CtdlDestroyMessageHook(void)
846 {
847         MessageFunctionHook *cur, *p;
848
849         cur = MessageHookTable; 
850         while (cur != NULL)
851         {
852                 MOD_syslog(LOG_DEBUG, "Destroyed message function (type %d)\n", cur->eventtype);
853                 p = cur->next;
854                 free(cur);
855                 cur = p;
856         }
857         MessageHookTable = NULL;
858 }
859
860
861 void CtdlRegisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
862 {
863         RoomFunctionHook *newfcn;
864
865         newfcn = (RoomFunctionHook *)
866             malloc(sizeof(RoomFunctionHook));
867         newfcn->next = RoomHookTable;
868         newfcn->fcn_ptr = fcn_ptr;
869         RoomHookTable = newfcn;
870
871         MODM_syslog(LOG_DEBUG, "Registered a new room function\n");
872 }
873
874
875 void CtdlUnregisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
876 {
877         RoomFunctionHook *cur, *p, *last;
878         last = NULL;
879         cur = RoomHookTable;
880         while (cur != NULL)
881         {
882                 if (fcn_ptr == cur->fcn_ptr) {
883                         MODM_syslog(LOG_DEBUG, "Unregistered room function\n");
884                         p = cur->next;
885
886                         free(cur);
887                         cur = NULL;
888
889                         if (last != NULL)
890                                 last->next = p;
891                         else 
892                                 RoomHookTable = p;
893                         cur = p;
894                 }
895                 else {
896                         last = cur;
897                         cur = cur->next;
898                 }
899         }
900 }
901
902
903 void CtdlDestroyRoomHooks(void)
904 {
905         RoomFunctionHook *cur, *p;
906
907         cur = RoomHookTable;
908         while (cur != NULL)
909         {
910                 MODM_syslog(LOG_DEBUG, "Destroyed room function\n");
911                 p = cur->next;
912                 free(cur);
913                 cur = p;
914         }
915         RoomHookTable = NULL;
916 }
917
918 void CtdlRegisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
919 {
920         NetprocFunctionHook *newfcn;
921
922         newfcn = (NetprocFunctionHook *)
923             malloc(sizeof(NetprocFunctionHook));
924         newfcn->next = NetprocHookTable;
925         newfcn->h_function_pointer = handler;
926         NetprocHookTable = newfcn;
927
928         MODM_syslog(LOG_DEBUG, "Registered a new netproc function\n");
929 }
930
931
932 void CtdlUnregisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
933 {
934         NetprocFunctionHook *cur, *p, *last;
935
936         cur = NetprocHookTable;
937         last = NULL;
938
939         while (cur != NULL) {
940                 if (handler == cur->h_function_pointer)
941                 {
942                         MODM_syslog(LOG_DEBUG, "Unregistered netproc function\n");
943                         p = cur->next;
944                         free(cur);
945                         if (last != NULL) {
946                                 last->next = p;
947                         }
948                         else {
949                                 NetprocHookTable = p;
950                         }
951                         cur = p;
952                 }
953                 else {
954                         last = cur;
955                         cur = cur->next;
956                 }
957         }
958 }
959
960 void CtdlDestroyNetprocHooks(void)
961 {
962         NetprocFunctionHook *cur, *p;
963
964         cur = NetprocHookTable;
965         while (cur != NULL)
966         {
967                 MODM_syslog(LOG_DEBUG, "Destroyed netproc function\n");
968                 p = cur->next;
969                 free(cur);
970                 cur = p;
971         }
972         NetprocHookTable = NULL;
973 }
974
975
976 void CtdlRegisterDeleteHook(void (*handler)(char *, long) )
977 {
978         DeleteFunctionHook *newfcn;
979
980         newfcn = (DeleteFunctionHook *)
981             malloc(sizeof(DeleteFunctionHook));
982         newfcn->next = DeleteHookTable;
983         newfcn->h_function_pointer = handler;
984         DeleteHookTable = newfcn;
985
986         MODM_syslog(LOG_DEBUG, "Registered a new delete function\n");
987 }
988
989
990 void CtdlUnregisterDeleteHook(void (*handler)(char *, long) )
991 {
992         DeleteFunctionHook *cur, *p, *last;
993
994         last = NULL;
995         cur = DeleteHookTable;
996         while (cur != NULL) {
997                 if (handler == cur->h_function_pointer )
998                 {
999                         MODM_syslog(LOG_DEBUG, "Unregistered delete function\n");
1000                         p = cur->next;
1001                         free(cur);
1002
1003                         if (last != NULL)
1004                                 last->next = p;
1005                         else
1006                                 DeleteHookTable = p;
1007
1008                         cur = p;
1009                 }
1010                 else {
1011                         last = cur;
1012                         cur = cur->next;
1013                 }
1014         }
1015 }
1016 void CtdlDestroyDeleteHooks(void)
1017 {
1018         DeleteFunctionHook *cur, *p;
1019
1020         cur = DeleteHookTable;
1021         while (cur != NULL)
1022         {
1023                 MODM_syslog(LOG_DEBUG, "Destroyed delete function\n");
1024                 p = cur->next;
1025                 free(cur);
1026                 cur = p;                
1027         }
1028         DeleteHookTable = NULL;
1029 }
1030
1031
1032
1033
1034 void CtdlRegisterFixedOutputHook(char *content_type, void (*handler)(char *, int) )
1035 {
1036         FixedOutputHook *newfcn;
1037
1038         newfcn = (FixedOutputHook *)
1039             malloc(sizeof(FixedOutputHook));
1040         newfcn->next = FixedOutputTable;
1041         newfcn->h_function_pointer = handler;
1042         safestrncpy(newfcn->content_type, content_type, sizeof newfcn->content_type);
1043         FixedOutputTable = newfcn;
1044
1045         MOD_syslog(LOG_DEBUG, "Registered a new fixed output function for %s\n", newfcn->content_type);
1046 }
1047
1048
1049 void CtdlUnregisterFixedOutputHook(char *content_type)
1050 {
1051         FixedOutputHook *cur, *p, *last;
1052
1053         last = NULL;
1054         cur = FixedOutputTable;
1055         while (cur != NULL) {
1056                 /* This will also remove duplicates if any */
1057                 if (!strcasecmp(content_type, cur->content_type)) {
1058                         MOD_syslog(LOG_DEBUG,
1059                                    "Unregistered fixed output function for %s\n",
1060                                    content_type);
1061
1062                         p = cur->next;
1063                         free(cur);
1064
1065                         if (last != NULL)
1066                                 last->next = p;
1067                         else
1068                                 FixedOutputTable = p;
1069                         
1070                         cur = p;
1071                 }
1072                 else
1073                 {
1074                         last = cur;
1075                         cur = cur->next;
1076                 }
1077         }
1078 }
1079
1080 void CtdlDestroyFixedOutputHooks(void)
1081 {
1082         FixedOutputHook *cur, *p;
1083
1084         cur = FixedOutputTable; 
1085         while (cur != NULL)
1086         {
1087                 MOD_syslog(LOG_DEBUG, "Destroyed fixed output function for %s\n", cur->content_type);
1088                 p = cur->next;
1089                 free(cur);
1090                 cur = p;
1091                 
1092         }
1093         FixedOutputTable = NULL;
1094 }
1095
1096 /* returns nonzero if we found a hook and used it */
1097 int PerformFixedOutputHooks(char *content_type, char *content, int content_length)
1098 {
1099         FixedOutputHook *fcn;
1100
1101         for (fcn = FixedOutputTable; fcn != NULL; fcn = fcn->next) {
1102                 if (!strcasecmp(content_type, fcn->content_type)) {
1103                         (*fcn->h_function_pointer) (content, content_length);
1104                         return(1);
1105                 }
1106         }
1107         return(0);
1108 }
1109
1110
1111
1112
1113
1114 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *, char *), int order)
1115 {
1116
1117         XmsgFunctionHook *newfcn;
1118
1119         newfcn = (XmsgFunctionHook *) malloc(sizeof(XmsgFunctionHook));
1120         newfcn->next = XmsgHookTable;
1121         newfcn->order = order;
1122         newfcn->h_function_pointer = fcn_ptr;
1123         XmsgHookTable = newfcn;
1124         MOD_syslog(LOG_DEBUG, "Registered a new x-msg function (priority %d)\n", order);
1125 }
1126
1127
1128 void CtdlUnregisterXmsgHook(int (*fcn_ptr) (char *, char *, char *, char *), int order)
1129 {
1130         XmsgFunctionHook *cur, *p, *last;
1131
1132         last = NULL;
1133         cur = XmsgHookTable;
1134         while (cur != NULL) {
1135                 /* This will also remove duplicates if any */
1136                 if (fcn_ptr == cur->h_function_pointer &&
1137                     order == cur->order) {
1138                         MOD_syslog(LOG_DEBUG, "Unregistered x-msg function "
1139                                    "(priority %d)\n", order);
1140                         p = cur->next;
1141                         free(cur);
1142
1143                         if (last != NULL)
1144                                 last->next = p;
1145                         else
1146                                 XmsgHookTable = p;
1147                         
1148                         cur = p;
1149                 }
1150                 else {
1151                         last = cur;
1152                         cur = cur->next;
1153                 }
1154         }
1155 }
1156
1157 void CtdlDestroyXmsgHooks(void)
1158 {
1159         XmsgFunctionHook *cur, *p;
1160
1161         cur = XmsgHookTable;
1162         while (cur != NULL)
1163         {
1164                 MOD_syslog(LOG_DEBUG, "Destroyed x-msg function "
1165                         "(priority %d)\n", cur->order);
1166                 p = cur->next;
1167                         
1168                 free(cur);
1169                 cur = p;
1170         }
1171         XmsgHookTable = NULL;
1172 }
1173
1174
1175 void CtdlRegisterServiceHook(int tcp_port,
1176                              char *sockpath,
1177                              void (*h_greeting_function) (void),
1178                              void (*h_command_function) (void),
1179                              void (*h_async_function) (void),
1180                              const char *ServiceName)
1181 {
1182         ServiceFunctionHook *newfcn;
1183         char *message;
1184         char error[SIZ];
1185
1186         strcpy(error, "");
1187         newfcn = (ServiceFunctionHook *) malloc(sizeof(ServiceFunctionHook));
1188         message = (char*) malloc (SIZ + SIZ);
1189         
1190         newfcn->next = ServiceHookTable;
1191         newfcn->tcp_port = tcp_port;
1192         newfcn->sockpath = sockpath;
1193         newfcn->h_greeting_function = h_greeting_function;
1194         newfcn->h_command_function = h_command_function;
1195         newfcn->h_async_function = h_async_function;
1196         newfcn->ServiceName = ServiceName;
1197
1198         if (sockpath != NULL) {
1199                 newfcn->msock = ctdl_uds_server(sockpath, config.c_maxsessions, error);
1200                 snprintf(message, SIZ, "Unix domain socket '%s': ", sockpath);
1201         }
1202         else if (tcp_port <= 0) {       /* port -1 to disable */
1203                 MOD_syslog(LOG_INFO, "Service %s has been manually disabled, skipping\n", ServiceName);
1204                 free (message);
1205                 free(newfcn);
1206                 return;
1207         }
1208         else {
1209                 newfcn->msock = ctdl_tcp_server(config.c_ip_addr,
1210                                               tcp_port,
1211                                               config.c_maxsessions, 
1212                                               error);
1213                 snprintf(message, SIZ, "TCP port %s:%d: (%s) ", 
1214                          config.c_ip_addr, tcp_port, ServiceName);
1215         }
1216
1217         if (newfcn->msock > 0) {
1218                 ServiceHookTable = newfcn;
1219                 strcat(message, "registered.");
1220                 MOD_syslog(LOG_INFO, "%s\n", message);
1221         }
1222         else {
1223                 AddPortError(message, error);
1224                 strcat(message, "FAILED.");
1225                 MOD_syslog(LOG_CRIT, "%s\n", message);
1226                 free(newfcn);
1227         }
1228         free(message);
1229 }
1230
1231
1232 void CtdlUnregisterServiceHook(int tcp_port, char *sockpath,
1233                         void (*h_greeting_function) (void),
1234                         void (*h_command_function) (void),
1235                         void (*h_async_function) (void)
1236                         )
1237 {
1238         ServiceFunctionHook *cur, *p, *last;
1239
1240         last = NULL;
1241         cur = ServiceHookTable;
1242         while (cur != NULL) {
1243                 /* This will also remove duplicates if any */
1244                 if (h_greeting_function == cur->h_greeting_function &&
1245                     h_command_function == cur->h_command_function &&
1246                     h_async_function == cur->h_async_function &&
1247                     tcp_port == cur->tcp_port && 
1248                     !(sockpath && cur->sockpath && strcmp(sockpath, cur->sockpath)) )
1249                 {
1250                         if (cur->msock > 0)
1251                                 close(cur->msock);
1252                         if (sockpath) {
1253                                 MOD_syslog(LOG_INFO, "Closed UNIX domain socket %s\n",
1254                                            sockpath);
1255                                 unlink(sockpath);
1256                         } else if (tcp_port) {
1257                                 MOD_syslog(LOG_INFO, "Closed TCP port %d\n", tcp_port);
1258                         } else {
1259                                 MOD_syslog(LOG_INFO, "Unregistered service \"%s\"\n", cur->ServiceName);
1260                         }
1261                         p = cur->next;
1262                         free(cur);
1263                         if (last != NULL)
1264                                 last->next = p;
1265                         else
1266                                 ServiceHookTable = p;
1267                         cur = p;
1268                 }
1269                 else {
1270                         last = cur;
1271                         cur = cur->next;
1272                 }
1273         }
1274 }
1275
1276
1277 void CtdlShutdownServiceHooks(void)
1278 {
1279         /* sort of a duplicate of close_masters() but called earlier */
1280         ServiceFunctionHook *cur;
1281
1282         cur = ServiceHookTable;
1283         while (cur != NULL) 
1284         {
1285                 if (cur->msock != -1)
1286                 {
1287                         close(cur->msock);
1288                         cur->msock = -1;
1289                         if (cur->sockpath != NULL){
1290                                 MOD_syslog(LOG_INFO, "[%s] Closed UNIX domain socket %s\n",
1291                                            cur->ServiceName,
1292                                            cur->sockpath);
1293                                 unlink(cur->sockpath);
1294                         } else {
1295                                 MOD_syslog(LOG_INFO, "[%s] closing service\n", 
1296                                            cur->ServiceName);
1297                         }
1298                 }
1299                 cur = cur->next;
1300         }
1301 }
1302
1303 void CtdlDestroyServiceHook(void)
1304 {
1305         const char *Text;
1306         ServiceFunctionHook *cur, *p;
1307
1308         cur = ServiceHookTable;
1309         while (cur != NULL)
1310         {
1311                 if (cur->msock != -1)
1312                 {
1313                         close(cur->msock);
1314                         Text = "Closed";
1315                 }
1316                 else
1317                 {
1318                         Text = " Not closing again";
1319                 }
1320
1321                 if (cur->sockpath) {
1322                         MOD_syslog(LOG_INFO, "%s UNIX domain socket %s\n",
1323                                    Text,
1324                                    cur->sockpath);
1325                         unlink(cur->sockpath);
1326                 } else if (cur->tcp_port) {
1327                         MOD_syslog(LOG_INFO, "%s TCP port %d\n", Text, cur->tcp_port);
1328                 } else {
1329                         MOD_syslog(LOG_INFO, "Destroyed service \"%s\"\n", cur->ServiceName);
1330                 }
1331                 p = cur->next;
1332                 free(cur);
1333                 cur = p;
1334         }
1335         ServiceHookTable = NULL;
1336 }
1337
1338 void CtdlRegisterSearchFuncHook(void (*fcn_ptr)(int *, long **, const char *), char *name)
1339 {
1340         SearchFunctionHook *newfcn;
1341
1342         if (!name || !fcn_ptr) {
1343                 return;
1344         }
1345         
1346         newfcn = (SearchFunctionHook *)
1347             malloc(sizeof(SearchFunctionHook));
1348         newfcn->next = SearchFunctionHookTable;
1349         newfcn->name = name;
1350         newfcn->fcn_ptr = fcn_ptr;
1351         SearchFunctionHookTable = newfcn;
1352
1353         MOD_syslog(LOG_DEBUG, "Registered a new search function (%s)\n", name);
1354 }
1355
1356 void CtdlUnregisterSearchFuncHook(void (*fcn_ptr)(int *, long **, const char *), char *name)
1357 {
1358         SearchFunctionHook *cur, *p, *last;
1359         
1360         last = NULL;
1361         cur = SearchFunctionHookTable;
1362         while (cur != NULL) {
1363                 if (fcn_ptr &&
1364                     (cur->fcn_ptr == fcn_ptr) &&
1365                     name && !strcmp(name, cur->name))
1366                 {
1367                         MOD_syslog(LOG_DEBUG, "Unregistered search function(%s)\n", name);
1368                         p = cur->next;
1369                         free (cur);
1370                         if (last != NULL)
1371                                 last->next = p;
1372                         else
1373                                 SearchFunctionHookTable = p;
1374                         cur = p;
1375                 }
1376                 else {
1377                         last = cur;
1378                         cur = cur->next;
1379                 }
1380         }
1381 }
1382
1383 void CtdlDestroySearchHooks(void)
1384 {
1385         SearchFunctionHook *cur, *p;
1386
1387         cur = SearchFunctionHookTable;
1388         SearchFunctionHookTable = NULL;
1389         while (cur != NULL) {
1390                 p = cur->next;
1391                 free(cur);
1392                 cur = p;
1393         }
1394 }
1395
1396 void CtdlModuleDoSearch(int *num_msgs, long **search_msgs, const char *search_string, const char *func_name)
1397 {
1398         SearchFunctionHook *fcn = NULL;
1399
1400         for (fcn = SearchFunctionHookTable; fcn != NULL; fcn = fcn->next) {
1401                 if (!func_name || !strcmp(func_name, fcn->name)) {
1402                         (*fcn->fcn_ptr) (num_msgs, search_msgs, search_string);
1403                         return;
1404                 }
1405         }
1406         *num_msgs = 0;
1407 }
1408
1409 int CheckTDAPVeto (int DBType, StrBuf *ErrMsg)
1410 {
1411         int Result = 0;
1412         TDAPVetoHookFunctionHook *fcn = NULL;
1413
1414         for (fcn = TDAPVetoHookTable; (fcn != NULL) && (Result == 0); fcn = fcn->next) {
1415                 if (fcn->eventtype == DBType) {
1416                         Result = (*fcn->h_function_pointer) (ErrMsg);
1417                 }
1418         }
1419         return Result;
1420 }
1421
1422 void PerformSessionHooks(int EventType)
1423 {
1424         SessionFunctionHook *fcn = NULL;
1425
1426         for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
1427                 if (fcn->eventtype == EventType) {
1428                         if (EventType == EVT_TIMER) {
1429                                 pthread_setspecific(MyConKey, NULL);    /* for every hook */
1430                         }
1431                         (*fcn->h_function_pointer) ();
1432                 }
1433         }
1434 }
1435
1436 void PerformUserHooks(ctdluser *usbuf, int EventType)
1437 {
1438         UserFunctionHook *fcn = NULL;
1439
1440         for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
1441                 if (fcn->eventtype == EventType) {
1442                         (*fcn->h_function_pointer) (usbuf);
1443                 }
1444         }
1445 }
1446
1447 int PerformMessageHooks(struct CtdlMessage *msg, int EventType)
1448 {
1449         MessageFunctionHook *fcn = NULL;
1450         int total_retval = 0;
1451
1452         /* Other code may elect to protect this message from server-side
1453          * handlers; if this is the case, don't do anything.
1454         MOD_syslog(LOG_DEBUG, "** Event type is %d, flags are %d\n", EventType, msg->cm_flags);
1455          */
1456         if (msg->cm_flags & CM_SKIP_HOOKS) {
1457                 MODM_syslog(LOG_DEBUG, "Skipping hooks\n");
1458                 return(0);
1459         }
1460
1461         /* Otherwise, run all the hooks appropriate to this event type.
1462          */
1463         for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) {
1464                 if (fcn->eventtype == EventType) {
1465                         total_retval = total_retval + (*fcn->h_function_pointer) (msg);
1466                 }
1467         }
1468
1469         /* Return the sum of the return codes from the hook functions.  If
1470          * this is an EVT_BEFORESAVE event, a nonzero return code will cause
1471          * the save operation to abort.
1472          */
1473         return total_retval;
1474 }
1475
1476
1477 int PerformRoomHooks(struct ctdlroom *target_room)
1478 {
1479         RoomFunctionHook *fcn;
1480         int total_retval = 0;
1481
1482         MOD_syslog(LOG_DEBUG, "Performing room hooks for <%s>\n", target_room->QRname);
1483
1484         for (fcn = RoomHookTable; fcn != NULL; fcn = fcn->next) {
1485                 total_retval = total_retval + (*fcn->fcn_ptr) (target_room);
1486         }
1487
1488         /* Return the sum of the return codes from the hook functions.
1489          */
1490         return total_retval;
1491 }
1492
1493
1494 int PerformNetprocHooks(struct CtdlMessage *msg, char *target_room)
1495 {
1496         NetprocFunctionHook *fcn;
1497         int total_retval = 0;
1498
1499         for (fcn = NetprocHookTable; fcn != NULL; fcn = fcn->next) {
1500                 total_retval = total_retval +
1501                         (*fcn->h_function_pointer) (msg, target_room);
1502         }
1503
1504         /* Return the sum of the return codes from the hook functions.
1505          * A nonzero return code will cause the message to *not* be imported.
1506          */
1507         return total_retval;
1508 }
1509
1510
1511 void PerformDeleteHooks(char *room, long msgnum)
1512 {
1513         DeleteFunctionHook *fcn;
1514
1515         for (fcn = DeleteHookTable; fcn != NULL; fcn = fcn->next) {
1516                 (*fcn->h_function_pointer) (room, msgnum);
1517         }
1518 }
1519
1520
1521
1522
1523
1524 int PerformXmsgHooks(char *sender, char *sender_email, char *recp, char *msg)
1525 {
1526         XmsgFunctionHook *fcn;
1527         int total_sent = 0;
1528         int p;
1529
1530         for (p=0; p<MAX_XMSG_PRI; ++p) {
1531                 for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
1532                         if (fcn->order == p) {
1533                                 total_sent +=
1534                                         (*fcn->h_function_pointer)
1535                                                 (sender, sender_email, recp, msg);
1536                         }
1537                 }
1538                 /* Break out of the loop if a higher-priority function
1539                  * successfully delivered the message.  This prevents duplicate
1540                  * deliveries to local users simultaneously signed onto
1541                  * remote services.
1542                  */
1543                 if (total_sent) break;
1544         }
1545         return total_sent;
1546 }
1547
1548
1549 /*
1550  * Dirty hack until we impliment a hook mechanism for this
1551  */
1552 void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response)
1553 {
1554 #ifdef HAVE_OPENSSL
1555         CtdlStartTLS (ok_response, nosup_response, error_response);
1556 #endif
1557 }
1558
1559 void DebugModulesEnable(const int n)
1560 {
1561         DebugModules = n;
1562 }
1563 CTDL_MODULE_INIT(modules)
1564 {
1565         if (!threading) {
1566                 CtdlRegisterDebugFlagHook(HKEY("modules"), DebugModulesEnable, &DebugModules);
1567
1568                 CtdlRegisterProtoHook(cmd_log_get, "LOGP", "Print Log-parameters");
1569                 CtdlRegisterProtoHook(cmd_log_set, "LOGS", "Set Log-parameters");
1570         }
1571         return "modules";
1572 }