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