1 /* -*- mode: C; mode: fold; -*- */
2 /*
3 This file is part of SLRN.
4 Copyright (c) 2001 Robin Sommer <rsommer@uni-paderborn.de>
5 Copyright (c) 2001-2006 Thomas Schultz <tststs@gmx.de>
6
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "config.h"
23 #include <string.h>
24 #include "slrnfeat.h"
25 #include "slrn.h"
26 #include "util.h"
27 #include "hooks.h"
28 #include "strutil.h"
29
30 typedef struct Hook_Function_Type
31 {
32 SLang_Name_Type *func;
33 struct Hook_Function_Type *next;
34 }
35 Hook_Function_Type;
36
37 typedef struct Hook_Type
38 {
39 const char *name;
40 int multi; /* whether multiple hooks may be registered */
41 Hook_Function_Type *first;
42 }
43 Hook_Type;
44
45 /* Order as given by constants HOOK_*
46 * Define whether or not multiple registration is allowed: */
47
48 static Hook_Type Hooks [HOOK_NUMBER+1] =
49 {
50 { "article_mode_hook", 1, NULL },
51 { "article_mode_quit_hook", 1, NULL },
52 { "article_mode_startup_hook", 1, NULL },
53 { "cc_hook", 0, NULL },
54 { "followup_hook", 1, NULL },
55 { "forward_hook", 1, NULL },
56 { "group_mode_hook", 1, NULL },
57 { "group_mode_startup_hook", 1, NULL },
58 { "header_number_hook", 1, NULL },
59 { "make_from_string_hook", 0, NULL },
60 { "make_save_filename_hook", 0, NULL },
61 { "post_file_hook", 1, NULL },
62 { "post_filter_hook", 1, NULL },
63 { "post_hook", 1, NULL },
64 { "pre_article_mode_hook", 1, NULL },
65 { "quit_hook", 1, NULL },
66 { "resize_screen_hook", 1, NULL },
67 { "read_article_hook", 1, NULL },
68 { "reply_hook", 1, NULL },
69 { "startup_hook", 1, NULL },
70 { "subject_compare_hook", 0, NULL },
71 { "supersede_hook", 1, NULL },
72
73 {NULL, 0, NULL}
74 };
75
find_hook(char * name)76 static Hook_Type *find_hook (char *name)
77 {
78 Hook_Type *h;
79
80 h = Hooks;
81 while (h->name != NULL)
82 {
83 if (0 == strcmp (name, h->name))
84 return h;
85 h++;
86 }
87 return NULL;
88 }
89
free_hook_function_type(Hook_Function_Type * f)90 static void free_hook_function_type (Hook_Function_Type *f)
91 {
92 if (f == NULL)
93 return;
94
95 if (f->func != NULL)
96 SLang_free_function (f->func);
97
98 slrn_free ((char *) f);
99 }
100
slrn_register_hook(char * name,SLang_Name_Type * func)101 int slrn_register_hook (char *name, SLang_Name_Type *func)
102 {
103 Hook_Type *h;
104 Hook_Function_Type *f;
105
106 if (NULL == (h = find_hook (name)))
107 return -1;
108
109 /* Do not register the same hook more than once */
110 f = h->first;
111 while (f != NULL)
112 {
113 if (f->func == func)
114 return 1;
115 f = f->next;
116 }
117
118 f = (Hook_Function_Type *) SLmalloc (sizeof (Hook_Function_Type));
119 if (f == NULL)
120 return -1;
121
122 if (NULL == (f->func = SLang_copy_function (func)))
123 {
124 SLfree ((char *) f);
125 return -1;
126 }
127
128 if (h->multi == 0)
129 {
130 free_hook_function_type (h->first);
131 h->first = NULL;
132 }
133
134 f->next = h->first;
135 h->first = f;
136
137 return 1;
138 }
139
slrn_unregister_hook(char * name,SLang_Name_Type * func)140 int slrn_unregister_hook (char *name, SLang_Name_Type *func)
141 {
142 Hook_Type *h;
143 Hook_Function_Type *f, *prev;
144
145 if (NULL == (h = find_hook (name)))
146 return -1;
147
148 prev = NULL;
149 f = h->first;
150 while (f != NULL)
151 {
152 if (f->func != func)
153 {
154 prev = f;
155 f = f->next;
156 continue;
157 }
158
159 if (prev != NULL)
160 prev->next = f->next;
161 else
162 h->first = f->next;
163
164 free_hook_function_type (f);
165 return 1;
166 }
167
168 return 0;
169 }
170
call_slang_function(SLang_Name_Type * func,unsigned int num_args,va_list ap)171 static int call_slang_function (SLang_Name_Type *func, unsigned int num_args, va_list ap)
172 {
173 unsigned int i;
174
175 if (-1 == SLang_start_arg_list ())
176 return -1;
177
178 for (i = 0; i < num_args; i++)
179 {
180 char *arg = va_arg (ap, char *);
181 if (-1 == SLang_push_string (arg))
182 return -1;
183 }
184
185 if ((-1 == SLang_end_arg_list ())
186 || (-1 == SLexecute_function (func)))
187 return -1;
188
189 return 0;
190 }
191
slrn_run_hooks(unsigned int hook,unsigned int num_args,...)192 int slrn_run_hooks (unsigned int hook, unsigned int num_args, ...)
193 {
194 SLang_Name_Type *func;
195 Hook_Function_Type *f;
196 Hook_Type *h;
197 va_list ap;
198 int num_called;
199
200 num_called = 0;
201
202 if (hook > HOOK_NUMBER)
203 return num_called;
204
205 h = Hooks + hook;
206 if (h->name == NULL)
207 return num_called;
208
209 f = h->first;
210 while (f != NULL)
211 {
212 va_start (ap, num_args);
213 if (-1 == call_slang_function (f->func, num_args, ap))
214 {
215 va_end (ap);
216 return -1;
217 }
218 va_end (ap);
219 f = f->next;
220 num_called++;
221 }
222
223 if (num_called && (h->multi == 0))
224 return num_called;
225
226 /* Compatibility */
227 if (NULL == (func = SLang_get_function ((char *)h->name)))
228 return num_called;
229
230 va_start (ap, num_args);
231 if (-1 == call_slang_function (func, num_args, ap))
232 {
233 va_end (ap);
234 SLang_free_function (func);
235 return -1;
236 }
237 va_end (ap);
238 SLang_free_function (func);
239 num_called++;
240
241 return num_called;
242 }
243
slrn_is_hook_defined(unsigned int hook)244 int slrn_is_hook_defined (unsigned int hook)
245 {
246 Hook_Type *h;
247
248 if (hook >= HOOK_NUMBER)
249 return 0;
250
251 h = Hooks + hook;
252
253 if (h->first != NULL)
254 return 1;
255
256 return ((h->name != NULL) && (SLang_is_defined ((char *)h->name) > 0));
257 }
258