Back to index

citadel  8.12
serv_extensions.c
Go to the documentation of this file.
00001 /*
00002  * Citadel Dynamic Loading Module
00003  * Written by Brian Costello <btx@calyx.net>
00004  *
00005  * Copyright (c) 1987-2011 by the citadel.org team
00006  *
00007  * This program is open source software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00020  */
00021 
00022 #include "sysdep.h"
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <unistd.h>
00026 #include <sys/types.h>
00027 #include <dirent.h>
00028 #include <string.h>
00029 #include <limits.h>
00030 #include <ctype.h>
00031 #include <syslog.h>
00032 #include <libcitadel.h>
00033 #include "citadel.h"
00034 #include "server.h"
00035 #include "serv_extensions.h"
00036 #include "sysdep_decls.h"
00037 #include "msgbase.h"
00038 #include "config.h"
00039 
00040 #include "modules/crypto/serv_crypto.h"   /* Needed until a universal crypto startup hook is implimented for CtdlStartTLS */
00041 
00042 #include "ctdl_module.h"
00043 
00044 #ifndef HAVE_SNPRINTF
00045 #include <stdarg.h>
00046 #include "snprintf.h"
00047 #endif
00048 
00049 int DebugModules = 0;
00050  
00051 /*
00052  * Structure defentitions for hook tables
00053  */
00054 
00055 typedef struct __LogDebugEntry {
00056        CtdlDbgFunction F;
00057        const char *Name;
00058        long Len;
00059        const int *LogP;
00060 } LogDebugEntry;
00061 HashList *LogDebugEntryTable = NULL;
00062 
00063 typedef struct LogFunctionHook LogFunctionHook;
00064 struct LogFunctionHook {
00065        LogFunctionHook *next;
00066        int loglevel;
00067        void (*h_function_pointer) (char *);
00068 };
00069 extern LogFunctionHook *LogHookTable;
00070 
00071 typedef struct FixedOutputHook FixedOutputHook;
00072 struct FixedOutputHook {
00073        FixedOutputHook *next;
00074        char content_type[64];
00075        void (*h_function_pointer) (char *, int);
00076 };
00077 extern FixedOutputHook *FixedOutputTable;
00078 
00079 
00080 
00081 /*
00082  * SessionFunctionHook extensions are used for any type of hook for which
00083  * the context in which it's being called (which is determined by the event
00084  * type) will make it obvious for the hook function to know where to look for
00085  * pertinent data.
00086  */
00087 typedef struct SessionFunctionHook SessionFunctionHook;
00088 struct SessionFunctionHook {
00089        SessionFunctionHook *next;
00090        int Priority;
00091        void (*h_function_pointer) (void);
00092        int eventtype;
00093 };
00094 extern SessionFunctionHook *SessionHookTable;
00095 
00096 
00097 /*
00098  * UserFunctionHook extensions are used for any type of hook which implements
00099  * an operation on a user or username (potentially) other than the one
00100  * operating the current session.
00101  */
00102 typedef struct UserFunctionHook UserFunctionHook;
00103 struct UserFunctionHook {
00104        UserFunctionHook *next;
00105        void (*h_function_pointer) (struct ctdluser *usbuf);
00106        int eventtype;
00107 };
00108 extern UserFunctionHook *UserHookTable;
00109 
00110 /*
00111  * MessageFunctionHook extensions are used for hooks which implement handlers
00112  * for various types of message operations (save, read, etc.)
00113  */
00114 typedef struct MessageFunctionHook MessageFunctionHook;
00115 struct MessageFunctionHook {
00116        MessageFunctionHook *next;
00117        int (*h_function_pointer) (struct CtdlMessage *msg);
00118        int eventtype;
00119 };
00120 extern MessageFunctionHook *MessageHookTable;
00121 
00122 
00123 /*
00124  * NetprocFunctionHook extensions are used for hooks which implement handlers
00125  * for incoming network messages.
00126  */
00127 typedef struct NetprocFunctionHook NetprocFunctionHook;
00128 struct NetprocFunctionHook {
00129        NetprocFunctionHook *next;
00130        int (*h_function_pointer) (struct CtdlMessage *msg, char *target_room);
00131 };
00132 extern NetprocFunctionHook *NetprocHookTable;
00133 
00134 
00135 /*
00136  * DeleteFunctionHook extensions are used for hooks which get called when a
00137  * message is about to be deleted.
00138  */
00139 typedef struct DeleteFunctionHook DeleteFunctionHook;
00140 struct DeleteFunctionHook {
00141        DeleteFunctionHook *next;
00142        void (*h_function_pointer) (char *target_room, long msgnum);
00143 };
00144 extern DeleteFunctionHook *DeleteHookTable;
00145 
00146 
00147 /*
00148  * ExpressMessageFunctionHook extensions are used for hooks which implement
00149  * the sending of an instant message through various channels.  Any function
00150  * registered should return the number of recipients to whom the message was
00151  * successfully transmitted.
00152  */
00153 typedef struct XmsgFunctionHook XmsgFunctionHook;
00154 struct XmsgFunctionHook {
00155        XmsgFunctionHook *next;
00156        int (*h_function_pointer) (char *, char *, char *, char *);
00157        int order;
00158 };
00159 extern XmsgFunctionHook *XmsgHookTable;
00160 
00161 
00162 
00163 
00164 /*
00165  * RoomFunctionHook extensions are used for hooks which impliment room
00166  * processing functions when new messages are added EG. SIEVE.
00167  */
00168 typedef struct RoomFunctionHook RoomFunctionHook;
00169 struct RoomFunctionHook {
00170        RoomFunctionHook *next;
00171        int (*fcn_ptr) (struct ctdlroom *);
00172 };
00173 extern RoomFunctionHook *RoomHookTable;
00174 
00175 
00176 
00177 typedef struct SearchFunctionHook SearchFunctionHook;
00178 struct SearchFunctionHook {
00179        SearchFunctionHook *next;
00180        void (*fcn_ptr) (int *, long **, const char *);
00181        char *name;
00182 };
00183 extern SearchFunctionHook *SearchFunctionHookTable;
00184 
00185 
00186 CleanupFunctionHook *CleanupHookTable = NULL;
00187 CleanupFunctionHook *EVCleanupHookTable = NULL;
00188 SessionFunctionHook *SessionHookTable = NULL;
00189 UserFunctionHook *UserHookTable = NULL;
00190 XmsgFunctionHook *XmsgHookTable = NULL;
00191 MessageFunctionHook *MessageHookTable = NULL;
00192 NetprocFunctionHook *NetprocHookTable = NULL;
00193 DeleteFunctionHook *DeleteHookTable = NULL;
00194 ServiceFunctionHook *ServiceHookTable = NULL;
00195 FixedOutputHook *FixedOutputTable = NULL;
00196 RoomFunctionHook *RoomHookTable = NULL;
00197 SearchFunctionHook *SearchFunctionHookTable = NULL;
00198 
00199 typedef struct ProtoFunctionHook ProtoFunctionHook;
00200 struct ProtoFunctionHook {
00201        void (*handler) (char *cmdbuf);
00202        const char *cmd;
00203        const char *desc;
00204 };
00205 
00206 HashList *ProtoHookList = NULL;
00207 
00208 
00209 #define ERR_PORT (1 << 1)
00210 
00211 
00212 static StrBuf *portlist = NULL;
00213 
00214 static StrBuf *errormessages = NULL;
00215 
00216 
00217 long   DetailErrorFlags;
00218 ConstStr Empty = {HKEY("")};
00219 char *ErrSubject = "Startup Problems";
00220 ConstStr ErrGeneral[] = {
00221        {HKEY("Citadel had trouble on starting up. ")},
00222        {HKEY(" This means, citadel won't be the service provider for a specific service you configured it to.\n\n"
00223              "If you don't want citadel to provide these services, turn them off in WebCit via: ")},
00224        {HKEY("To make both ways actualy take place restart the citserver with \"sendcommand down\"\n\n"
00225              "The errors returned by the system were:\n")},
00226        {HKEY("You can recheck the above if you follow this faq item:\n"
00227              "http://www.citadel.org/doku.php?id=faq:mastering_your_os:net#netstat")}
00228 };
00229 
00230 ConstStr ErrPortShort = { HKEY("We couldn't bind all ports you configured to be provided by citadel server.\n")};
00231 ConstStr ErrPortWhere = { HKEY("\"Admin->System Preferences->Network\".\n\nThe failed ports and sockets are: ")};
00232 ConstStr ErrPortHint  = { HKEY("If you want citadel to provide you with that functionality, "
00233                             "check the output of \"netstat -lnp\" on linux Servers or \"netstat -na\" on *BSD"
00234                             " and stop the program that binds these ports.\n You should eventually remove "
00235                             " their initscripts in /etc/init.d so that you won't get this trouble once more.\n"
00236                             " After that goto \"Administration -> Shutdown Citadel\" to make Citadel restart & retry to bind this port.\n")};
00237 
00238 
00239 void LogPrintMessages(long err)
00240 {
00241        StrBuf *Message;
00242        StrBuf *List, *DetailList;
00243        ConstStr *Short, *Where, *Hint; 
00244 
00245        
00246        Message = NewStrBufPlain(NULL, 
00247                              StrLength(portlist) + StrLength(errormessages));
00248        
00249        DetailErrorFlags = DetailErrorFlags & ~err;
00250 
00251        switch (err)
00252        {
00253        case ERR_PORT:
00254               Short = &ErrPortShort;
00255               Where = &ErrPortWhere;
00256               Hint  = &ErrPortHint;
00257               List  = portlist;
00258               DetailList = errormessages;
00259               break;
00260        default:
00261               Short = &Empty;
00262               Where = &Empty;
00263               Hint  = &Empty;
00264               List  = NULL;
00265               DetailList = NULL;
00266        }
00267 
00268        StrBufAppendBufPlain(Message, CKEY(ErrGeneral[0]), 0);
00269        StrBufAppendBufPlain(Message, CKEY(*Short), 0);  
00270        StrBufAppendBufPlain(Message, CKEY(ErrGeneral[1]), 0);
00271        StrBufAppendBufPlain(Message, CKEY(*Where), 0);
00272        StrBufAppendBuf(Message, List, 0);
00273        StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
00274        StrBufAppendBufPlain(Message, CKEY(*Hint), 0);
00275        StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
00276        StrBufAppendBufPlain(Message, CKEY(ErrGeneral[2]), 0);
00277        StrBufAppendBuf(Message, DetailList, 0);
00278        StrBufAppendBufPlain(Message, HKEY("\n\n"), 0);
00279        StrBufAppendBufPlain(Message, CKEY(ErrGeneral[3]), 0);
00280 
00281        MOD_syslog(LOG_EMERG, "%s", ChrPtr(Message));
00282        MOD_syslog(LOG_EMERG, "%s", ErrSubject);
00283        quickie_message("Citadel", NULL, NULL, AIDEROOM, ChrPtr(Message), FMT_FIXED, ErrSubject);
00284 
00285        FreeStrBuf(&Message);
00286        FreeStrBuf(&List);
00287        FreeStrBuf(&DetailList);
00288 }
00289 
00290 
00291 void AddPortError(char *Port, char *ErrorMessage)
00292 {
00293        long len;
00294 
00295        DetailErrorFlags |= ERR_PORT;
00296 
00297        len = StrLength(errormessages);
00298        if (len > 0) StrBufAppendBufPlain(errormessages, HKEY("; "), 0);
00299        else errormessages = NewStrBuf();
00300        StrBufAppendBufPlain(errormessages, ErrorMessage, -1, 0);
00301 
00302 
00303        len = StrLength(portlist);
00304        if (len > 0) StrBufAppendBufPlain(portlist, HKEY(";"), 0);
00305        else portlist = NewStrBuf();
00306        StrBufAppendBufPlain(portlist, Port, -1, 0);
00307 }
00308 
00309 
00310 int DLoader_Exec_Cmd(char *cmdbuf)
00311 {
00312        void *vP;
00313        ProtoFunctionHook *p;
00314 
00315        if (GetHash(ProtoHookList, cmdbuf, 4, &vP) && (vP != NULL)) {
00316               p = (ProtoFunctionHook*) vP;
00317               p->handler(&cmdbuf[5]);
00318               return 1;
00319        }
00320        return 0;
00321 }
00322 
00323 long FourHash(const char *key, long length) 
00324 {
00325        int i;
00326        int ret = 0;
00327        const unsigned char *ptr = (const unsigned char*)key;
00328 
00329        for (i = 0; i < 4; i++, ptr ++) 
00330               ret = (ret << 8) | 
00331                      ( ((*ptr >= 'a') &&
00332                         (*ptr <= 'z'))? 
00333                        *ptr - 'a' + 'A': 
00334                        *ptr);
00335 
00336        return ret;
00337 }
00338 
00339 void CtdlRegisterDebugFlagHook(const char *Name, long Len, CtdlDbgFunction F, const int *LogP)
00340 {
00341        LogDebugEntry *E;
00342        if (LogDebugEntryTable == NULL)
00343               LogDebugEntryTable = NewHash(1, NULL);
00344        E = (LogDebugEntry*) malloc(sizeof(LogDebugEntry));
00345        E->F = F;
00346        E->Name = Name;
00347        E->Len = Len;
00348        E->LogP = LogP;
00349        Put(LogDebugEntryTable, Name, Len, E, NULL);
00350        
00351 }
00352 void CtdlSetDebugLogFacilities(const char **Str, long n)
00353 {
00354        StrBuf *Token = NULL;
00355        StrBuf *Buf = NULL;
00356        const char *ch;
00357        int i;
00358        int DoAll = 0;
00359        void *vptr;
00360 
00361        for (i=0; i < n; i++){
00362               if ((Str[i] != NULL) && !IsEmptyStr(Str[i])) {
00363                      if (strcmp(Str[i], "all") == 0) {
00364                             DoAll = 1;
00365                             continue;
00366                      }
00367                      Buf = NewStrBufPlain(Str[i], -1);
00368                      ch = NULL;
00369                      if (Token == NULL)
00370                             Token = NewStrBufPlain(NULL, StrLength(Buf));
00371                      while ((ch != StrBufNOTNULL) &&
00372                             StrBufExtract_NextToken(Token, Buf, &ch, ',')) {
00373                             if (GetHash(LogDebugEntryTable, SKEY(Token), &vptr) && 
00374                                 (vptr != NULL))
00375                             {
00376                                    LogDebugEntry *E = (LogDebugEntry*)vptr;
00377                                    E->F(1);
00378                             }
00379                      }
00380               }
00381               FreeStrBuf(&Buf);
00382        }
00383        FreeStrBuf(&Token);
00384        if (DoAll) {
00385               long HKLen;
00386               const char *ch;
00387               HashPos *Pos;
00388 
00389               Pos = GetNewHashPos(LogDebugEntryTable, 0);
00390               while (GetNextHashPos(LogDebugEntryTable, Pos, &HKLen, &ch, &vptr)) {
00391                      LogDebugEntry *E = (LogDebugEntry*)vptr;
00392                      E->F(1);
00393               }
00394 
00395               DeleteHashPos(&Pos);
00396        }
00397 }
00398 void cmd_log_get(char *argbuf)
00399 {
00400        long HKLen;
00401        const char *ch;
00402        HashPos *Pos;
00403        void *vptr;
00404 
00405        if (CtdlAccessCheck(ac_aide)) return;
00406 
00407        cprintf("%d Log modules enabled:\n", LISTING_FOLLOWS);
00408 
00409        Pos = GetNewHashPos(LogDebugEntryTable, 0);
00410 
00411        while (GetNextHashPos(LogDebugEntryTable, Pos, &HKLen, &ch, &vptr)) {
00412               LogDebugEntry *E = (LogDebugEntry*)vptr;
00413               cprintf("%s|%d\n", ch, *E->LogP);
00414        }
00415        
00416        DeleteHashPos(&Pos);
00417        cprintf("000\n");
00418 }
00419 void cmd_log_set(char *argbuf)
00420 {
00421        void *vptr;
00422        int lset;
00423        int wlen;
00424        char which[SIZ] = "";
00425 
00426        if (CtdlAccessCheck(ac_aide)) return;
00427 
00428        wlen = extract_token(which, argbuf, 0, '|', sizeof(which));
00429        if (wlen < 0) wlen = 0;
00430        lset = extract_int(argbuf, 1);
00431        if (lset != 0) lset = 1;
00432        if (GetHash(LogDebugEntryTable, which, wlen, &vptr) && 
00433            (vptr != NULL))
00434        {
00435               LogDebugEntry *E = (LogDebugEntry*)vptr;
00436               E->F(lset);
00437               cprintf("%d %s|%d\n", CIT_OK, which, lset);
00438        }
00439        else {
00440               cprintf("%d Log setting %s not known\n", 
00441                      ERROR, which);
00442        }
00443 }
00444 void CtdlDestroyDebugTable(void)
00445 {
00446 
00447        DeleteHash(&LogDebugEntryTable);
00448 }
00449 
00450 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
00451 {
00452        ProtoFunctionHook *p;
00453 
00454        if (ProtoHookList == NULL)
00455               ProtoHookList = NewHash (1, FourHash);
00456 
00457 
00458        p = (ProtoFunctionHook *)
00459               malloc(sizeof(ProtoFunctionHook));
00460 
00461        if (p == NULL) {
00462               fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
00463               exit(EXIT_FAILURE);
00464        }
00465        p->handler = handler;
00466        p->cmd = cmd;
00467        p->desc = desc;
00468 
00469        Put(ProtoHookList, cmd, 4, p, NULL);
00470        MOD_syslog(LOG_DEBUG, "Registered server command %s (%s)\n", cmd, desc);
00471 }
00472 
00473 void CtdlDestroyProtoHooks(void)
00474 {
00475 
00476        DeleteHash(&ProtoHookList);
00477 }
00478 
00479 
00480 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
00481 {
00482 
00483        CleanupFunctionHook *newfcn;
00484 
00485        newfcn = (CleanupFunctionHook *)
00486            malloc(sizeof(CleanupFunctionHook));
00487        newfcn->next = CleanupHookTable;
00488        newfcn->h_function_pointer = fcn_ptr;
00489        CleanupHookTable = newfcn;
00490 
00491        MODM_syslog(LOG_DEBUG, "Registered a new cleanup function\n");
00492 }
00493 
00494 
00495 void CtdlUnregisterCleanupHook(void (*fcn_ptr) (void))
00496 {
00497        CleanupFunctionHook *cur, *p, *last;
00498        last = NULL;
00499        cur = CleanupHookTable;
00500        while (cur != NULL)
00501        {
00502               if (fcn_ptr == cur->h_function_pointer)
00503               {
00504                      MODM_syslog(LOG_DEBUG, "Unregistered cleanup function\n");
00505                      p = cur->next;
00506 
00507                      free(cur);
00508                      cur = NULL;
00509 
00510                      if (last != NULL)
00511                             last->next = p;
00512                      else 
00513                             CleanupHookTable = p;
00514                      cur = p;
00515               }
00516               else {
00517                      last = cur;
00518                      cur = cur->next;
00519               }
00520        }
00521 }
00522 
00523 
00524 void CtdlDestroyCleanupHooks(void)
00525 {
00526        CleanupFunctionHook *cur, *p;
00527 
00528        cur = CleanupHookTable;
00529        while (cur != NULL)
00530        {
00531               MODM_syslog(LOG_DEBUG, "Destroyed cleanup function\n");
00532               p = cur->next;
00533               free(cur);
00534               cur = p;
00535        }
00536        CleanupHookTable = NULL;
00537 }
00538 
00539 void CtdlRegisterEVCleanupHook(void (*fcn_ptr) (void))
00540 {
00541 
00542        CleanupFunctionHook *newfcn;
00543 
00544        newfcn = (CleanupFunctionHook *)
00545            malloc(sizeof(CleanupFunctionHook));
00546        newfcn->next = EVCleanupHookTable;
00547        newfcn->h_function_pointer = fcn_ptr;
00548        EVCleanupHookTable = newfcn;
00549 
00550        MODM_syslog(LOG_DEBUG, "Registered a new cleanup function\n");
00551 }
00552 
00553 
00554 void CtdlUnregisterEVCleanupHook(void (*fcn_ptr) (void))
00555 {
00556        CleanupFunctionHook *cur, *p, *last;
00557        last = NULL;
00558        cur = EVCleanupHookTable;
00559        while (cur != NULL)
00560        {
00561               if (fcn_ptr == cur->h_function_pointer)
00562               {
00563                      MODM_syslog(LOG_DEBUG, "Unregistered cleanup function\n");
00564                      p = cur->next;
00565 
00566                      free(cur);
00567                      cur = NULL;
00568 
00569                      if (last != NULL)
00570                             last->next = p;
00571                      else 
00572                             EVCleanupHookTable = p;
00573                      cur = p;
00574               }
00575               else {
00576                      last = cur;
00577                      cur = cur->next;
00578               }
00579        }
00580 }
00581 
00582 
00583 void CtdlDestroyEVCleanupHooks(void)
00584 {
00585        CleanupFunctionHook *cur, *p;
00586 
00587        cur = EVCleanupHookTable;
00588        while (cur != NULL)
00589        {
00590               MODM_syslog(LOG_DEBUG, "Destroyed cleanup function\n");
00591               p = cur->next;
00592               free(cur);
00593               cur = p;
00594        }
00595        EVCleanupHookTable = NULL;
00596 }
00597 
00598 
00599 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType, int Priority)
00600 {
00601        SessionFunctionHook *newfcn;
00602 
00603        newfcn = (SessionFunctionHook *)
00604            malloc(sizeof(SessionFunctionHook));
00605        newfcn->Priority = Priority;
00606        newfcn->h_function_pointer = fcn_ptr;
00607        newfcn->eventtype = EventType;
00608 
00609        SessionFunctionHook **pfcn;
00610        pfcn = &SessionHookTable;
00611        while ((*pfcn != NULL) && 
00612               ((*pfcn)->Priority < newfcn->Priority) &&
00613               ((*pfcn)->next != NULL))
00614               pfcn = &(*pfcn)->next;
00615               
00616        newfcn->next = *pfcn;
00617        *pfcn = newfcn;
00618        
00619        MOD_syslog(LOG_DEBUG, "Registered a new session function (type %d Priority %d)\n",
00620                  EventType, Priority);
00621 }
00622 
00623 
00624 void CtdlUnregisterSessionHook(void (*fcn_ptr) (void), int EventType)
00625 {
00626        SessionFunctionHook *cur, *p, *last;
00627        last = NULL;
00628        cur = SessionHookTable;
00629        while  (cur != NULL) {
00630               if ((fcn_ptr == cur->h_function_pointer) &&
00631                   (EventType == cur->eventtype))
00632               {
00633                      MOD_syslog(LOG_DEBUG, "Unregistered session function (type %d)\n",
00634                                EventType);
00635                      p = cur->next;
00636 
00637                      free(cur);
00638                      cur = NULL;
00639 
00640                      if (last != NULL)
00641                             last->next = p;
00642                      else 
00643                             SessionHookTable = p;
00644                      cur = p;
00645               }
00646               else {
00647                      last = cur;
00648                      cur = cur->next;
00649               }
00650        }
00651 }
00652 
00653 void CtdlDestroySessionHooks(void)
00654 {
00655        SessionFunctionHook *cur, *p;
00656 
00657        cur = SessionHookTable;
00658        while (cur != NULL)
00659        {
00660               MODM_syslog(LOG_DEBUG, "Destroyed session function\n");
00661               p = cur->next;
00662               free(cur);
00663               cur = p;
00664        }
00665        SessionHookTable = NULL;
00666 }
00667 
00668 
00669 void CtdlRegisterUserHook(void (*fcn_ptr) (ctdluser *), int EventType)
00670 {
00671 
00672        UserFunctionHook *newfcn;
00673 
00674        newfcn = (UserFunctionHook *)
00675            malloc(sizeof(UserFunctionHook));
00676        newfcn->next = UserHookTable;
00677        newfcn->h_function_pointer = fcn_ptr;
00678        newfcn->eventtype = EventType;
00679        UserHookTable = newfcn;
00680 
00681        MOD_syslog(LOG_DEBUG, "Registered a new user function (type %d)\n",
00682                  EventType);
00683 }
00684 
00685 
00686 void CtdlUnregisterUserHook(void (*fcn_ptr) (struct ctdluser *), int EventType)
00687 {
00688        UserFunctionHook *cur, *p, *last;
00689        last = NULL;
00690        cur = UserHookTable;
00691        while (cur != NULL) {
00692               if ((fcn_ptr == cur->h_function_pointer) &&
00693                   (EventType == cur->eventtype))
00694               {
00695                      MOD_syslog(LOG_DEBUG, "Unregistered user function (type %d)\n",
00696                                EventType);
00697                      p = cur->next;
00698 
00699                      free(cur);
00700                      cur = NULL;
00701 
00702                      if (last != NULL)
00703                             last->next = p;
00704                      else 
00705                             UserHookTable = p;
00706                      cur = p;
00707               }
00708               else {
00709                      last = cur;
00710                      cur = cur->next;
00711               }
00712        }
00713 }
00714 
00715 void CtdlDestroyUserHooks(void)
00716 {
00717        UserFunctionHook *cur, *p;
00718 
00719        cur = UserHookTable;
00720        while (cur != NULL)
00721        {
00722               MODM_syslog(LOG_DEBUG, "Destroyed user function \n");
00723               p = cur->next;
00724               free(cur);
00725               cur = p;
00726        }
00727        UserHookTable = NULL;
00728 }
00729 
00730 
00731 void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *),
00732                             int EventType)
00733 {
00734 
00735        MessageFunctionHook *newfcn;
00736 
00737        newfcn = (MessageFunctionHook *)
00738            malloc(sizeof(MessageFunctionHook));
00739        newfcn->next = MessageHookTable;
00740        newfcn->h_function_pointer = handler;
00741        newfcn->eventtype = EventType;
00742        MessageHookTable = newfcn;
00743 
00744        MOD_syslog(LOG_DEBUG, "Registered a new message function (type %d)\n",
00745                  EventType);
00746 }
00747 
00748 
00749 void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *),
00750               int EventType)
00751 {
00752        MessageFunctionHook *cur, *p, *last;
00753        last = NULL;
00754        cur = MessageHookTable;
00755        while (cur != NULL) {
00756               if ((handler == cur->h_function_pointer) &&
00757                   (EventType == cur->eventtype))
00758               {
00759                      MOD_syslog(LOG_DEBUG, "Unregistered message function (type %d)\n",
00760                                EventType);
00761                      p = cur->next;
00762                      free(cur);
00763                      cur = NULL;
00764 
00765                      if (last != NULL)
00766                             last->next = p;
00767                      else 
00768                             MessageHookTable = p;
00769                      cur = p;
00770               }
00771               else {
00772                      last = cur;
00773                      cur = cur->next;
00774               }
00775        }
00776 }
00777 
00778 void CtdlDestroyMessageHook(void)
00779 {
00780        MessageFunctionHook *cur, *p;
00781 
00782        cur = MessageHookTable; 
00783        while (cur != NULL)
00784        {
00785               MOD_syslog(LOG_DEBUG, "Destroyed message function (type %d)\n", cur->eventtype);
00786               p = cur->next;
00787               free(cur);
00788               cur = p;
00789        }
00790        MessageHookTable = NULL;
00791 }
00792 
00793 
00794 void CtdlRegisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
00795 {
00796        RoomFunctionHook *newfcn;
00797 
00798        newfcn = (RoomFunctionHook *)
00799            malloc(sizeof(RoomFunctionHook));
00800        newfcn->next = RoomHookTable;
00801        newfcn->fcn_ptr = fcn_ptr;
00802        RoomHookTable = newfcn;
00803 
00804        MODM_syslog(LOG_DEBUG, "Registered a new room function\n");
00805 }
00806 
00807 
00808 void CtdlUnregisterRoomHook(int (*fcn_ptr)(struct ctdlroom *))
00809 {
00810        RoomFunctionHook *cur, *p, *last;
00811        last = NULL;
00812        cur = RoomHookTable;
00813        while (cur != NULL)
00814        {
00815               if (fcn_ptr == cur->fcn_ptr) {
00816                      MODM_syslog(LOG_DEBUG, "Unregistered room function\n");
00817                      p = cur->next;
00818 
00819                      free(cur);
00820                      cur = NULL;
00821 
00822                      if (last != NULL)
00823                             last->next = p;
00824                      else 
00825                             RoomHookTable = p;
00826                      cur = p;
00827               }
00828               else {
00829                      last = cur;
00830                      cur = cur->next;
00831               }
00832        }
00833 }
00834 
00835 
00836 void CtdlDestroyRoomHooks(void)
00837 {
00838        RoomFunctionHook *cur, *p;
00839 
00840        cur = RoomHookTable;
00841        while (cur != NULL)
00842        {
00843               MODM_syslog(LOG_DEBUG, "Destroyed room function\n");
00844               p = cur->next;
00845               free(cur);
00846               cur = p;
00847        }
00848        RoomHookTable = NULL;
00849 }
00850 
00851 void CtdlRegisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
00852 {
00853        NetprocFunctionHook *newfcn;
00854 
00855        newfcn = (NetprocFunctionHook *)
00856            malloc(sizeof(NetprocFunctionHook));
00857        newfcn->next = NetprocHookTable;
00858        newfcn->h_function_pointer = handler;
00859        NetprocHookTable = newfcn;
00860 
00861        MODM_syslog(LOG_DEBUG, "Registered a new netproc function\n");
00862 }
00863 
00864 
00865 void CtdlUnregisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) )
00866 {
00867        NetprocFunctionHook *cur, *p, *last;
00868 
00869        cur = NetprocHookTable;
00870        last = NULL;
00871 
00872        while (cur != NULL) {
00873               if (handler == cur->h_function_pointer)
00874               {
00875                      MODM_syslog(LOG_DEBUG, "Unregistered netproc function\n");
00876                      p = cur->next;
00877                      free(cur);
00878                      if (last != NULL) {
00879                             last->next = p;
00880                      }
00881                      else {
00882                             NetprocHookTable = p;
00883                      }
00884                      cur = p;
00885               }
00886               else {
00887                      last = cur;
00888                      cur = cur->next;
00889               }
00890        }
00891 }
00892 
00893 void CtdlDestroyNetprocHooks(void)
00894 {
00895        NetprocFunctionHook *cur, *p;
00896 
00897        cur = NetprocHookTable;
00898        while (cur != NULL)
00899        {
00900               MODM_syslog(LOG_DEBUG, "Destroyed netproc function\n");
00901               p = cur->next;
00902               free(cur);
00903               cur = p;
00904        }
00905        NetprocHookTable = NULL;
00906 }
00907 
00908 
00909 void CtdlRegisterDeleteHook(void (*handler)(char *, long) )
00910 {
00911        DeleteFunctionHook *newfcn;
00912 
00913        newfcn = (DeleteFunctionHook *)
00914            malloc(sizeof(DeleteFunctionHook));
00915        newfcn->next = DeleteHookTable;
00916        newfcn->h_function_pointer = handler;
00917        DeleteHookTable = newfcn;
00918 
00919        MODM_syslog(LOG_DEBUG, "Registered a new delete function\n");
00920 }
00921 
00922 
00923 void CtdlUnregisterDeleteHook(void (*handler)(char *, long) )
00924 {
00925        DeleteFunctionHook *cur, *p, *last;
00926 
00927        last = NULL;
00928        cur = DeleteHookTable;
00929        while (cur != NULL) {
00930               if (handler == cur->h_function_pointer )
00931               {
00932                      MODM_syslog(LOG_DEBUG, "Unregistered delete function\n");
00933                      p = cur->next;
00934                      free(cur);
00935 
00936                      if (last != NULL)
00937                             last->next = p;
00938                      else
00939                             DeleteHookTable = p;
00940 
00941                      cur = p;
00942               }
00943               else {
00944                      last = cur;
00945                      cur = cur->next;
00946               }
00947        }
00948 }
00949 void CtdlDestroyDeleteHooks(void)
00950 {
00951        DeleteFunctionHook *cur, *p;
00952 
00953        cur = DeleteHookTable;
00954        while (cur != NULL)
00955        {
00956               MODM_syslog(LOG_DEBUG, "Destroyed delete function\n");
00957               p = cur->next;
00958               free(cur);
00959               cur = p;             
00960        }
00961        DeleteHookTable = NULL;
00962 }
00963 
00964 
00965 
00966 
00967 void CtdlRegisterFixedOutputHook(char *content_type, void (*handler)(char *, int) )
00968 {
00969        FixedOutputHook *newfcn;
00970 
00971        newfcn = (FixedOutputHook *)
00972            malloc(sizeof(FixedOutputHook));
00973        newfcn->next = FixedOutputTable;
00974        newfcn->h_function_pointer = handler;
00975        safestrncpy(newfcn->content_type, content_type, sizeof newfcn->content_type);
00976        FixedOutputTable = newfcn;
00977 
00978        MOD_syslog(LOG_DEBUG, "Registered a new fixed output function for %s\n", newfcn->content_type);
00979 }
00980 
00981 
00982 void CtdlUnregisterFixedOutputHook(char *content_type)
00983 {
00984        FixedOutputHook *cur, *p, *last;
00985 
00986        last = NULL;
00987        cur = FixedOutputTable;
00988        while (cur != NULL) {
00989               /* This will also remove duplicates if any */
00990               if (!strcasecmp(content_type, cur->content_type)) {
00991                      MOD_syslog(LOG_DEBUG,
00992                                "Unregistered fixed output function for %s\n",
00993                                content_type);
00994 
00995                      p = cur->next;
00996                      free(cur);
00997 
00998                      if (last != NULL)
00999                             last->next = p;
01000                      else
01001                             FixedOutputTable = p;
01002                      
01003                      cur = p;
01004               }
01005               else
01006               {
01007                      last = cur;
01008                      cur = cur->next;
01009               }
01010        }
01011 }
01012 
01013 void CtdlDestroyFixedOutputHooks(void)
01014 {
01015        FixedOutputHook *cur, *p;
01016 
01017        cur = FixedOutputTable; 
01018        while (cur != NULL)
01019        {
01020               MOD_syslog(LOG_DEBUG, "Destroyed fixed output function for %s\n", cur->content_type);
01021               p = cur->next;
01022               free(cur);
01023               cur = p;
01024               
01025        }
01026        FixedOutputTable = NULL;
01027 }
01028 
01029 /* returns nonzero if we found a hook and used it */
01030 int PerformFixedOutputHooks(char *content_type, char *content, int content_length)
01031 {
01032        FixedOutputHook *fcn;
01033 
01034        for (fcn = FixedOutputTable; fcn != NULL; fcn = fcn->next) {
01035               if (!strcasecmp(content_type, fcn->content_type)) {
01036                      (*fcn->h_function_pointer) (content, content_length);
01037                      return(1);
01038               }
01039        }
01040        return(0);
01041 }
01042 
01043 
01044 
01045 
01046 
01047 void CtdlRegisterXmsgHook(int (*fcn_ptr) (char *, char *, char *, char *), int order)
01048 {
01049 
01050        XmsgFunctionHook *newfcn;
01051 
01052        newfcn = (XmsgFunctionHook *) malloc(sizeof(XmsgFunctionHook));
01053        newfcn->next = XmsgHookTable;
01054        newfcn->order = order;
01055        newfcn->h_function_pointer = fcn_ptr;
01056        XmsgHookTable = newfcn;
01057        MOD_syslog(LOG_DEBUG, "Registered a new x-msg function (priority %d)\n", order);
01058 }
01059 
01060 
01061 void CtdlUnregisterXmsgHook(int (*fcn_ptr) (char *, char *, char *, char *), int order)
01062 {
01063        XmsgFunctionHook *cur, *p, *last;
01064 
01065        last = NULL;
01066        cur = XmsgHookTable;
01067        while (cur != NULL) {
01068               /* This will also remove duplicates if any */
01069               if (fcn_ptr == cur->h_function_pointer &&
01070                   order == cur->order) {
01071                      MOD_syslog(LOG_DEBUG, "Unregistered x-msg function "
01072                                "(priority %d)\n", order);
01073                      p = cur->next;
01074                      free(cur);
01075 
01076                      if (last != NULL)
01077                             last->next = p;
01078                      else
01079                             XmsgHookTable = p;
01080                      
01081                      cur = p;
01082               }
01083               else {
01084                      last = cur;
01085                      cur = cur->next;
01086               }
01087        }
01088 }
01089 
01090 void CtdlDestroyXmsgHooks(void)
01091 {
01092        XmsgFunctionHook *cur, *p;
01093 
01094        cur = XmsgHookTable;
01095        while (cur != NULL)
01096        {
01097               MOD_syslog(LOG_DEBUG, "Destroyed x-msg function "
01098                      "(priority %d)\n", cur->order);
01099               p = cur->next;
01100                      
01101               free(cur);
01102               cur = p;
01103        }
01104        XmsgHookTable = NULL;
01105 }
01106 
01107 
01108 void CtdlRegisterServiceHook(int tcp_port,
01109                           char *sockpath,
01110                           void (*h_greeting_function) (void),
01111                           void (*h_command_function) (void),
01112                           void (*h_async_function) (void),
01113                           const char *ServiceName)
01114 {
01115        ServiceFunctionHook *newfcn;
01116        char *message;
01117        char error[SIZ];
01118 
01119        strcpy(error, "");
01120        newfcn = (ServiceFunctionHook *) malloc(sizeof(ServiceFunctionHook));
01121        message = (char*) malloc (SIZ + SIZ);
01122        
01123        newfcn->next = ServiceHookTable;
01124        newfcn->tcp_port = tcp_port;
01125        newfcn->sockpath = sockpath;
01126        newfcn->h_greeting_function = h_greeting_function;
01127        newfcn->h_command_function = h_command_function;
01128        newfcn->h_async_function = h_async_function;
01129        newfcn->ServiceName = ServiceName;
01130 
01131        if (sockpath != NULL) {
01132               newfcn->msock = ctdl_uds_server(sockpath, config.c_maxsessions, error);
01133               snprintf(message, SIZ, "Unix domain socket '%s': ", sockpath);
01134        }
01135        else if (tcp_port <= 0) {   /* port -1 to disable */
01136               MOD_syslog(LOG_INFO, "Service %s has been manually disabled, skipping\n", ServiceName);
01137               free (message);
01138               free(newfcn);
01139               return;
01140        }
01141        else {
01142               newfcn->msock = ctdl_tcp_server(config.c_ip_addr,
01143                                          tcp_port,
01144                                          config.c_maxsessions, 
01145                                          error);
01146               snprintf(message, SIZ, "TCP port %s:%d: (%s) ", 
01147                       config.c_ip_addr, tcp_port, ServiceName);
01148        }
01149 
01150        if (newfcn->msock > 0) {
01151               ServiceHookTable = newfcn;
01152               strcat(message, "registered.");
01153               MOD_syslog(LOG_INFO, "%s\n", message);
01154        }
01155        else {
01156               AddPortError(message, error);
01157               strcat(message, "FAILED.");
01158               MOD_syslog(LOG_CRIT, "%s\n", message);
01159               free(newfcn);
01160        }
01161        free(message);
01162 }
01163 
01164 
01165 void CtdlUnregisterServiceHook(int tcp_port, char *sockpath,
01166                      void (*h_greeting_function) (void),
01167                      void (*h_command_function) (void),
01168                      void (*h_async_function) (void)
01169                      )
01170 {
01171        ServiceFunctionHook *cur, *p, *last;
01172 
01173        last = NULL;
01174        cur = ServiceHookTable;
01175        while (cur != NULL) {
01176               /* This will also remove duplicates if any */
01177               if (h_greeting_function == cur->h_greeting_function &&
01178                   h_command_function == cur->h_command_function &&
01179                   h_async_function == cur->h_async_function &&
01180                   tcp_port == cur->tcp_port && 
01181                   !(sockpath && cur->sockpath && strcmp(sockpath, cur->sockpath)) )
01182               {
01183                      if (cur->msock > 0)
01184                             close(cur->msock);
01185                      if (sockpath) {
01186                             MOD_syslog(LOG_INFO, "Closed UNIX domain socket %s\n",
01187                                       sockpath);
01188                             unlink(sockpath);
01189                      } else if (tcp_port) {
01190                             MOD_syslog(LOG_INFO, "Closed TCP port %d\n", tcp_port);
01191                      } else {
01192                             MOD_syslog(LOG_INFO, "Unregistered service \"%s\"\n", cur->ServiceName);
01193                      }
01194                      p = cur->next;
01195                      free(cur);
01196                      if (last != NULL)
01197                             last->next = p;
01198                      else
01199                             ServiceHookTable = p;
01200                      cur = p;
01201               }
01202               else {
01203                      last = cur;
01204                      cur = cur->next;
01205               }
01206        }
01207 }
01208 
01209 
01210 void CtdlShutdownServiceHooks(void)
01211 {
01212        /* sort of a duplicate of close_masters() but called earlier */
01213        ServiceFunctionHook *cur;
01214 
01215        cur = ServiceHookTable;
01216        while (cur != NULL) 
01217        {
01218               if (cur->msock != -1)
01219               {
01220                      close(cur->msock);
01221                      cur->msock = -1;
01222                      if (cur->sockpath != NULL){
01223                             MOD_syslog(LOG_INFO, "[%s] Closed UNIX domain socket %s\n",
01224                                       cur->ServiceName,
01225                                       cur->sockpath);
01226                             unlink(cur->sockpath);
01227                      } else {
01228                             MOD_syslog(LOG_INFO, "[%s] closing service\n", 
01229                                       cur->ServiceName);
01230                      }
01231               }
01232               cur = cur->next;
01233        }
01234 }
01235 
01236 void CtdlDestroyServiceHook(void)
01237 {
01238        ServiceFunctionHook *cur, *p;
01239 
01240        cur = ServiceHookTable;
01241        while (cur != NULL)
01242        {
01243               close(cur->msock);
01244               if (cur->sockpath) {
01245                      MOD_syslog(LOG_INFO, "Closed UNIX domain socket %s\n",
01246                                cur->sockpath);
01247                      unlink(cur->sockpath);
01248               } else if (cur->tcp_port) {
01249                      MOD_syslog(LOG_INFO, "Closed TCP port %d\n", cur->tcp_port);
01250               } else {
01251                      MOD_syslog(LOG_INFO, "Destroyed service \"%s\"\n", cur->ServiceName);
01252               }
01253               p = cur->next;
01254               free(cur);
01255               cur = p;
01256        }
01257        ServiceHookTable = NULL;
01258 }
01259 
01260 void CtdlRegisterSearchFuncHook(void (*fcn_ptr)(int *, long **, const char *), char *name)
01261 {
01262        SearchFunctionHook *newfcn;
01263 
01264        if (!name || !fcn_ptr) {
01265               return;
01266        }
01267        
01268        newfcn = (SearchFunctionHook *)
01269            malloc(sizeof(SearchFunctionHook));
01270        newfcn->next = SearchFunctionHookTable;
01271        newfcn->name = name;
01272        newfcn->fcn_ptr = fcn_ptr;
01273        SearchFunctionHookTable = newfcn;
01274 
01275        MOD_syslog(LOG_DEBUG, "Registered a new search function (%s)\n", name);
01276 }
01277 
01278 void CtdlUnregisterSearchFuncHook(void (*fcn_ptr)(int *, long **, const char *), char *name)
01279 {
01280        SearchFunctionHook *cur, *p, *last;
01281        
01282        last = NULL;
01283        cur = SearchFunctionHookTable;
01284        while (cur != NULL) {
01285               if (fcn_ptr &&
01286                   (cur->fcn_ptr == fcn_ptr) &&
01287                   name && !strcmp(name, cur->name))
01288               {
01289                      MOD_syslog(LOG_DEBUG, "Unregistered search function(%s)\n", name);
01290                      p = cur->next;
01291                      free (cur);
01292                      if (last != NULL)
01293                             last->next = p;
01294                      else
01295                             SearchFunctionHookTable = p;
01296                      cur = p;
01297               }
01298               else {
01299                      last = cur;
01300                      cur = cur->next;
01301               }
01302        }
01303 }
01304 
01305 void CtdlDestroySearchHooks(void)
01306 {
01307         SearchFunctionHook *cur, *p;
01308 
01309        cur = SearchFunctionHookTable;
01310        SearchFunctionHookTable = NULL;
01311         while (cur != NULL) {
01312               p = cur->next;
01313               free(cur);
01314               cur = p;
01315        }
01316 }
01317 
01318 void CtdlModuleDoSearch(int *num_msgs, long **search_msgs, const char *search_string, const char *func_name)
01319 {
01320        SearchFunctionHook *fcn = NULL;
01321 
01322        for (fcn = SearchFunctionHookTable; fcn != NULL; fcn = fcn->next) {
01323               if (!func_name || !strcmp(func_name, fcn->name)) {
01324                      (*fcn->fcn_ptr) (num_msgs, search_msgs, search_string);
01325                      return;
01326               }
01327        }
01328        *num_msgs = 0;
01329 }
01330 
01331 
01332 void PerformSessionHooks(int EventType)
01333 {
01334        SessionFunctionHook *fcn = NULL;
01335 
01336        for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
01337               if (fcn->eventtype == EventType) {
01338                      if (EventType == EVT_TIMER) {
01339                             pthread_setspecific(MyConKey, NULL);      /* for every hook */
01340                      }
01341                      (*fcn->h_function_pointer) ();
01342               }
01343        }
01344 }
01345 
01346 void PerformUserHooks(ctdluser *usbuf, int EventType)
01347 {
01348        UserFunctionHook *fcn = NULL;
01349 
01350        for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
01351               if (fcn->eventtype == EventType) {
01352                      (*fcn->h_function_pointer) (usbuf);
01353               }
01354        }
01355 }
01356 
01357 int PerformMessageHooks(struct CtdlMessage *msg, int EventType)
01358 {
01359        MessageFunctionHook *fcn = NULL;
01360        int total_retval = 0;
01361 
01362        /* Other code may elect to protect this message from server-side
01363         * handlers; if this is the case, don't do anything.
01364        MOD_syslog(LOG_DEBUG, "** Event type is %d, flags are %d\n", EventType, msg->cm_flags);
01365         */
01366        if (msg->cm_flags & CM_SKIP_HOOKS) {
01367               MODM_syslog(LOG_DEBUG, "Skipping hooks\n");
01368               return(0);
01369        }
01370 
01371        /* Otherwise, run all the hooks appropriate to this event type.
01372         */
01373        for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) {
01374               if (fcn->eventtype == EventType) {
01375                      total_retval = total_retval + (*fcn->h_function_pointer) (msg);
01376               }
01377        }
01378 
01379        /* Return the sum of the return codes from the hook functions.  If
01380         * this is an EVT_BEFORESAVE event, a nonzero return code will cause
01381         * the save operation to abort.
01382         */
01383        return total_retval;
01384 }
01385 
01386 
01387 int PerformRoomHooks(struct ctdlroom *target_room)
01388 {
01389        RoomFunctionHook *fcn;
01390        int total_retval = 0;
01391 
01392        MOD_syslog(LOG_DEBUG, "Performing room hooks for <%s>\n", target_room->QRname);
01393 
01394        for (fcn = RoomHookTable; fcn != NULL; fcn = fcn->next) {
01395               total_retval = total_retval + (*fcn->fcn_ptr) (target_room);
01396        }
01397 
01398        /* Return the sum of the return codes from the hook functions.
01399         */
01400        return total_retval;
01401 }
01402 
01403 
01404 int PerformNetprocHooks(struct CtdlMessage *msg, char *target_room)
01405 {
01406        NetprocFunctionHook *fcn;
01407        int total_retval = 0;
01408 
01409        for (fcn = NetprocHookTable; fcn != NULL; fcn = fcn->next) {
01410               total_retval = total_retval +
01411                      (*fcn->h_function_pointer) (msg, target_room);
01412        }
01413 
01414        /* Return the sum of the return codes from the hook functions.
01415         * A nonzero return code will cause the message to *not* be imported.
01416         */
01417        return total_retval;
01418 }
01419 
01420 
01421 void PerformDeleteHooks(char *room, long msgnum)
01422 {
01423        DeleteFunctionHook *fcn;
01424 
01425        for (fcn = DeleteHookTable; fcn != NULL; fcn = fcn->next) {
01426               (*fcn->h_function_pointer) (room, msgnum);
01427        }
01428 }
01429 
01430 
01431 
01432 
01433 
01434 int PerformXmsgHooks(char *sender, char *sender_email, char *recp, char *msg)
01435 {
01436        XmsgFunctionHook *fcn;
01437        int total_sent = 0;
01438        int p;
01439 
01440        for (p=0; p<MAX_XMSG_PRI; ++p) {
01441               for (fcn = XmsgHookTable; fcn != NULL; fcn = fcn->next) {
01442                      if (fcn->order == p) {
01443                             total_sent +=
01444                                    (*fcn->h_function_pointer)
01445                                           (sender, sender_email, recp, msg);
01446                      }
01447               }
01448               /* Break out of the loop if a higher-priority function
01449                * successfully delivered the message.  This prevents duplicate
01450                * deliveries to local users simultaneously signed onto
01451                * remote services.
01452                */
01453               if (total_sent) break;
01454        }
01455        return total_sent;
01456 }
01457 
01458 
01459 /*
01460  * Dirty hack until we impliment a hook mechanism for this
01461  */
01462 void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response)
01463 {
01464 #ifdef HAVE_OPENSSL
01465        CtdlStartTLS (ok_response, nosup_response, error_response);
01466 #endif
01467 }
01468 
01469 void DebugModulesEnable(const int n)
01470 {
01471        DebugModules = n;
01472 }
01473 CTDL_MODULE_INIT(modules)
01474 {
01475        if (!threading) {
01476               CtdlRegisterDebugFlagHook(HKEY("modules"), DebugModulesEnable, &DebugModules);
01477 
01478               CtdlRegisterProtoHook(cmd_log_get, "LOGP", "Print Log-parameters");
01479               CtdlRegisterProtoHook(cmd_log_set, "LOGS", "Set Log-parameters");
01480        }
01481        return "modules";
01482 }