Changes to dynloader et al to handle ICQ module being written
[citadel.git] / citadel / dynloader.c
1 /*******************************************************
2  *
3  * Citadel Dynamic Loading Module
4  * Written by Brian Costello
5  * btx@calyx.net
6  *
7  * $Id$
8  *
9  ******************************************************/
10
11
12 #include "sysdep.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <dlfcn.h>
16 #include <sys/types.h>
17 #include <dirent.h>
18 #include <strings.h>
19 #include <syslog.h>
20 #ifdef HAVE_PTHREAD_H
21 #include <pthread.h>
22 #endif
23 #include <limits.h>
24 #include <ctype.h>
25 #include "dynloader.h"
26 #include "citadel.h"
27 #include "server.h"
28 #include "sysdep_decls.h"
29 #include "tools.h"
30
31 #ifndef HAVE_SNPRINTF
32 #include <stdarg.h>
33 #include "snprintf.h"
34 #endif
35
36 struct LogFunctionHook *LogHookTable = NULL;
37 struct CleanupFunctionHook *CleanupHookTable = NULL;
38 struct SessionFunctionHook *SessionHookTable = NULL;
39 struct UserFunctionHook *UserHookTable = NULL;
40
41 struct ProtoFunctionHook {
42         void (*handler) (char *cmdbuf);
43         char *cmd;
44         char *desc;
45         struct ProtoFunctionHook *next;
46 } *ProtoHookList = NULL;
47
48 void CtdlRegisterProtoHook(void (*handler) (char *), char *cmd, char *desc)
49 {
50         struct ProtoFunctionHook *p = mallok(sizeof *p);
51
52         if (p == NULL) {
53                 fprintf(stderr, "can't malloc new ProtoFunctionHook\n");
54                 exit(EXIT_FAILURE);
55         }
56         p->handler = handler;
57         p->cmd = cmd;
58         p->desc = desc;
59         p->next = ProtoHookList;
60         ProtoHookList = p;
61 }
62
63 int DLoader_Exec_Cmd(char *cmdbuf)
64 {
65         struct ProtoFunctionHook *p;
66
67         for (p = ProtoHookList; p; p = p->next) {
68                 if (!strncasecmp(cmdbuf, p->cmd, 4)) {
69                         p->handler(&cmdbuf[5]);
70                         return 1;
71                 }
72         }
73         return 0;
74 }
75
76 void DLoader_Init(char *pathname)
77 {
78         void *fcn_handle;
79         char dl_error[256];
80         DIR *dir;
81         int i;
82         struct dirent *dptr;
83         struct DLModule_Info *(*h_init_fcn) (void);
84         struct DLModule_Info *dl_info;
85
86         char pathbuf[PATH_MAX];
87
88         if ((dir = opendir(pathname)) == NULL) {
89                 perror("opendir");
90                 exit(1);
91         }
92         while ((dptr = readdir(dir)) != NULL) {
93                 if (dptr->d_name[0] == '.')
94                         continue;
95                 lprintf(9, "Attempting to load %s\n", dptr->d_name);
96
97                 snprintf(pathbuf, PATH_MAX, "%s/%s", pathname, dptr->d_name);
98 #ifdef RTLD_NOW
99                 if (!(fcn_handle = dlopen(pathbuf, RTLD_NOW)))
100 #else                           /* OpenBSD */
101                 if (!(fcn_handle = dlopen(pathbuf, DL_LAZY)))
102 #endif
103                 {
104                         safestrncpy(dl_error, dlerror(), sizeof dl_error);
105                         for (i=0; i<strlen(dl_error); ++i)
106                                 if (!isprint(dl_error[i]))
107                                         dl_error[i]='.';
108                         fprintf(stderr, "DLoader_Init dlopen failed: %s\n",
109                                 dl_error);
110                         continue;
111                 }
112                 h_init_fcn = (struct DLModule_Info * (*)(void))
113 #ifndef __OpenBSD__
114                     dlsym(fcn_handle, "Dynamic_Module_Init");
115 #else
116                     dlsym(fcn_handle, "_Dynamic_Module_Init");
117 #endif
118
119                 if (dlerror() != NULL) {
120                         fprintf(stderr, "DLoader_Init dlsym failed\n");
121                         continue;
122                 }
123                 dl_info = h_init_fcn();
124
125                 printf("Loaded module: %s v%d.%d\nBy %s (%s)\n", dl_info->module_name,
126                        dl_info->major_version, dl_info->minor_version,
127                    dl_info->module_author, dl_info->module_author_email);
128         }                       /* While */
129 }
130
131
132
133 void CtdlRegisterLogHook(void (*fcn_ptr) (char *), int loglevel)
134 {
135
136         struct LogFunctionHook *newfcn;
137
138         newfcn = (struct LogFunctionHook *)
139             mallok(sizeof(struct LogFunctionHook));
140         newfcn->next = LogHookTable;
141         newfcn->h_function_pointer = fcn_ptr;
142         newfcn->loglevel = loglevel;
143         LogHookTable = newfcn;
144
145         lprintf(5, "Registered a new logging function\n");
146 }
147
148
149 void CtdlRegisterCleanupHook(void (*fcn_ptr) (void))
150 {
151
152         struct CleanupFunctionHook *newfcn;
153
154         newfcn = (struct CleanupFunctionHook *)
155             mallok(sizeof(struct CleanupFunctionHook));
156         newfcn->next = CleanupHookTable;
157         newfcn->h_function_pointer = fcn_ptr;
158         CleanupHookTable = newfcn;
159
160         lprintf(5, "Registered a new cleanup function\n");
161 }
162
163
164 void CtdlRegisterSessionHook(void (*fcn_ptr) (void), int EventType)
165 {
166
167         struct SessionFunctionHook *newfcn;
168
169         newfcn = (struct SessionFunctionHook *)
170             mallok(sizeof(struct SessionFunctionHook));
171         newfcn->next = SessionHookTable;
172         newfcn->h_function_pointer = fcn_ptr;
173         newfcn->eventtype = EventType;
174         SessionHookTable = newfcn;
175
176         lprintf(5, "Registered a new session function (type %d)\n",
177                 EventType);
178 }
179
180
181 void CtdlRegisterUserHook(void (*fcn_ptr) (char *, long), int EventType)
182 {
183
184         struct UserFunctionHook *newfcn;
185
186         newfcn = (struct UserFunctionHook *)
187             mallok(sizeof(struct UserFunctionHook));
188         newfcn->next = UserHookTable;
189         newfcn->h_function_pointer = fcn_ptr;
190         newfcn->eventtype = EventType;
191         UserHookTable = newfcn;
192
193         lprintf(5, "Registered a new user function (type %d)\n",
194                 EventType);
195 }
196
197
198 void PerformSessionHooks(int EventType)
199 {
200         struct SessionFunctionHook *fcn;
201
202         for (fcn = SessionHookTable; fcn != NULL; fcn = fcn->next) {
203                 if (fcn->eventtype == EventType) {
204                         (*fcn->h_function_pointer) ();
205                 }
206         }
207 }
208
209 void PerformLogHooks(int loglevel, char *logmsg)
210 {
211         struct LogFunctionHook *fcn;
212
213         for (fcn = LogHookTable; fcn != NULL; fcn = fcn->next) {
214                 if (fcn->loglevel >= loglevel) {
215                         (*fcn->h_function_pointer) (logmsg);
216                 }
217         }
218 }
219
220 void PerformUserHooks(char *username, long usernum, int EventType)
221 {
222         struct UserFunctionHook *fcn;
223
224         for (fcn = UserHookTable; fcn != NULL; fcn = fcn->next) {
225                 if (fcn->eventtype == EventType) {
226                         (*fcn->h_function_pointer) (username, usernum);
227                 }
228         }
229 }