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