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