ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hybrid-ircservices-1/send.c
Revision: 1209
Committed: Thu Aug 25 19:05:49 2011 UTC (14 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 10191 byte(s)
Log Message:
- run everything thru indent
  "-bli0 -di1 -npcs -nut -cdw -bls -nbbo -bap"

File Contents

# User Rev Content
1 michael 1194 /* Routines for sending stuff to the network.
2     *
3     * IRC Services is copyright (c) 1996-2009 Andrew Church.
4     * E-mail: <achurch@achurch.org>
5     * Parts written by Andrew Kempe and others.
6     * This program is free but copyrighted software; see the file GPL.txt for
7     * details.
8     */
9    
10     #define IN_SEND_C
11     #include "services.h"
12     #include "modules.h"
13     #include "language.h"
14    
15     /*************************************************************************/
16    
17 michael 1209 time_t last_send; /* Time last data was sent to server */
18 michael 1194
19    
20     /* Modes to send for Services users. */
21     const char *pseudoclient_modes = "";
22     const char *enforcer_modes = "";
23     /* Do "oper" pseudoclients really need oper privileges? (1 or 0) */
24     int pseudoclient_oper = 1;
25    
26    
27     /* Default handler for module-implemented functions. */
28     static void unimplemented(void);
29    
30     /* Functions which are to be implemented by protocol modules. See
31     * documentation for details. */
32     FUNCPTR(void, send_nick, (const char *nick, const char *user,
33     const char *host, const char *server,
34     const char *name, const char *modes))
35 michael 1209 = (void *) unimplemented;
36 michael 1194 FUNCPTR(void, send_nickchange, (const char *nick, const char *newnick))
37 michael 1209 = (void *) unimplemented;
38 michael 1194 FUNCPTR(void, send_namechange, (const char *nick, const char *newname))
39 michael 1209 = (void *) unimplemented;
40     FUNCPTR(void, send_server, (void)) = (void *) unimplemented;
41 michael 1194 FUNCPTR(void, send_server_remote, (const char *server, const char *desc))
42 michael 1209 = (void *) unimplemented;
43 michael 1194 FUNCPTR(void, wallops, (const char *source, const char *fmt, ...)
44 michael 1209 FORMAT(printf, 2, 3)) = (void *) unimplemented;
45 michael 1194 FUNCPTR(void, notice_all, (const char *source, const char *fmt, ...)
46 michael 1209 FORMAT(printf, 2, 3)) = (void *) unimplemented;
47 michael 1194 FUNCPTR(void, send_channel_cmd, (const char *source, const char *fmt, ...)
48 michael 1209 FORMAT(printf, 2, 3)) = (void *) unimplemented;
49 michael 1194 FUNCPTR(void, send_nickchange_remote, (const char *nick, const char *newnick))
50 michael 1209 = (void *) unimplemented;
51 michael 1194
52     /*************************************************************************/
53    
54     /* Initialization: set up protocol_* variables, and verify on load that the
55     * protocol module set everything up correctly.
56     */
57    
58 michael 1209 const char *protocol_name = NULL;
59 michael 1194 const char *protocol_version = NULL;
60 michael 1209 uint32 protocol_features = PF_UNSET;
61     int protocol_nickmax = 0;
62 michael 1194
63     #define PROTOCHK(var) \
64     if (!var) \
65     fatal("Variable `" #var "' not set by protocol module `%s'", name);
66     #define FUNCCHK(var) \
67     if ((void *)var == (void *)unimplemented) \
68     fatal("Function `" #var "' not set by protocol module `%s'", name);
69    
70 michael 1209 static int
71     do_load_module(Module * mod, const char *name)
72 michael 1194 {
73 michael 1209 /* Assume the first module loaded is a protocol module */
74 michael 1194
75 michael 1209 PROTOCHK(protocol_name);
76     if (protocol_features & PF_UNSET)
77     fatal("Variable `protocol_features' not set by protocol module `%s'",
78     name);
79     PROTOCHK(protocol_nickmax);
80 michael 1194
81 michael 1209 FUNCCHK(send_nick);
82     FUNCCHK(send_nickchange);
83     FUNCCHK(send_namechange);
84     FUNCCHK(send_server);
85     FUNCCHK(send_server_remote);
86     FUNCCHK(wallops);
87     FUNCCHK(notice_all);
88     FUNCCHK(send_channel_cmd);
89     if (protocol_features & PF_CHANGENICK)
90     FUNCCHK(send_nickchange_remote);
91 michael 1194
92 michael 1209 /* Make sure NICKMAX is large enough to hold the largest nickname
93     * supported by the protocol plus a trailing NULL. */
94     if (protocol_nickmax + 1 > NICKMAX)
95     fatal("NICKMAX is too small (%d)--increase to at least %d and"
96     " recompile", NICKMAX, protocol_nickmax + 1);
97 michael 1194
98 michael 1209 /* Remove the callback now that everything's checked. */
99     remove_callback(NULL, "load module", do_load_module);
100 michael 1194
101 michael 1209 return 0;
102 michael 1194 }
103    
104     #undef FUNCCHK
105     #undef PROTOCHK
106    
107    
108 michael 1209 int
109     send_init(int ac, char **av)
110 michael 1194 {
111 michael 1209 if (!add_callback(NULL, "load module", do_load_module))
112     {
113     log("send.c: Unable to add load module callback");
114     return 0;
115     }
116     return 1;
117 michael 1194 }
118    
119     /*************************************************************************/
120    
121     /* Cleanup. */
122    
123 michael 1209 void
124     send_cleanup(void)
125 michael 1194 {
126 michael 1209 remove_callback(NULL, "load module", do_load_module);
127 michael 1194 }
128    
129     /*************************************************************************/
130     /*************************************************************************/
131    
132     /* Send a command to the server. The two forms here are like
133     * printf()/vprintf() and friends. If not connected to a remote server,
134     * these functions do nothing.
135     */
136    
137 michael 1209 void
138     send_cmd(const char *source, const char *fmt, ...)
139 michael 1194 {
140 michael 1209 va_list args;
141 michael 1194
142 michael 1209 va_start(args, fmt);
143     vsend_cmd(source, fmt, args);
144     va_end(args);
145 michael 1194 }
146    
147 michael 1209 void
148     vsend_cmd(const char *source, const char *fmt, va_list args)
149 michael 1194 {
150 michael 1209 char buf[BUFSIZE];
151 michael 1194
152 michael 1209 if (!servsock)
153     return;
154     vsnprintf(buf, sizeof(buf), fmt, args);
155     if (source)
156     {
157     if (servsock)
158     sockprintf(servsock, ":%s %s\r\n", source, buf);
159     log_debug(1, "Sent: :%s %s", source, buf);
160     }
161     else
162     {
163     if (servsock)
164     sockprintf(servsock, "%s\r\n", buf);
165     log_debug(1, "Sent: %s", buf);
166     }
167     last_send = time(NULL);
168 michael 1194 }
169    
170     /*************************************************************************/
171     /*************************************************************************/
172    
173     /* Send an ERROR message and close the connection to the server. */
174    
175 michael 1209 void
176     send_error(const char *fmt, ...)
177 michael 1194 {
178 michael 1209 va_list args;
179     char buf[BUFSIZE];
180 michael 1194
181 michael 1209 snprintf(buf, sizeof(buf), "ERROR :%s", fmt);
182     va_start(args, fmt);
183     vsend_cmd(NULL, buf, args);
184     va_end(args);
185     disconn(servsock);
186 michael 1194 }
187    
188     /*************************************************************************/
189    
190     /* Send a command to change channel modes. (Needed to handle various
191     * varieties of timestamping. We currently cheat and use a timestamp of
192     * zero to force our modes through.)
193     */
194    
195 michael 1209 void
196     send_cmode_cmd(const char *source, const char *channel, const char *fmt, ...)
197 michael 1194 {
198 michael 1209 va_list args;
199     char buf[BUFSIZE];
200 michael 1194
201 michael 1209 va_start(args, fmt);
202     vsnprintf(buf, sizeof(buf), fmt, args);
203     va_end(args);
204     if (protocol_features & PF_MODETS_FIRST)
205     send_channel_cmd(source, "MODE %s 0 %s", channel, buf);
206     else
207     send_channel_cmd(source, "MODE %s %s", channel, buf);
208 michael 1194 }
209    
210     /*************************************************************************/
211    
212     /* Introduce a pseudoclient nickname. `flags' includes PSEUDO_OPER if the
213     * pseudoclient requires IRC operator privileges (however, the client may
214     * not actually get +o if the server does not require it), and PSEUDO_INVIS
215     * if the pseudoclient should be invisible (+i).
216     */
217    
218 michael 1209 void
219     send_pseudo_nick(const char *nick, const char *realname, int flags)
220 michael 1194 {
221 michael 1209 char modebuf[BUFSIZE];
222 michael 1194
223 michael 1209 snprintf(modebuf, sizeof(modebuf), "%s%s%s",
224     pseudoclient_modes,
225     (flags & PSEUDO_OPER) && pseudoclient_oper ? "o" : "",
226     (flags & PSEUDO_INVIS) ? "i" : "");
227     send_nick(nick, ServiceUser, ServiceHost, ServerName, realname, modebuf);
228 michael 1194 }
229    
230     /*************************************************************************/
231    
232     /* Send a NOTICE from the given source to the given nick. */
233    
234 michael 1209 void
235     notice(const char *source, const char *dest, const char *fmt, ...)
236 michael 1194 {
237 michael 1209 va_list args;
238     char buf[BUFSIZE];
239 michael 1194
240 michael 1209 va_start(args, fmt);
241     vsnprintf(buf, sizeof(buf), fmt, args);
242     va_end(args);
243     send_cmd(source, "NOTICE %s :%s", dest, buf);
244 michael 1194 }
245    
246    
247     /* Send a NULL-terminated array of text as NOTICEs. */
248    
249 michael 1209 void
250     notice_list(const char *source, const char *dest, const char **text)
251 michael 1194 {
252 michael 1209 while (*text)
253     {
254     /* Have to kludge around client/server silliness here: if a notice
255     * includes no text, it is ignored, so we replace blank lines by
256     * lines with a single space. */
257     if (**text)
258     notice(source, dest, *text);
259     else
260     notice(source, dest, " ");
261     text++;
262     }
263 michael 1194 }
264    
265    
266     /* Send a message in the user's selected language to the user using NOTICE. */
267    
268 michael 1209 void
269     notice_lang(const char *source, const User * dest, int message, ...)
270 michael 1194 {
271 michael 1209 va_list args;
272     char buf[4096]; /* because messages can be really big */
273     char *s, *t;
274     const char *fmt;
275 michael 1194
276 michael 1209 if (!dest)
277     return;
278     fmt = getstring(dest->ngi, message);
279     if (!fmt)
280     return;
281     va_start(args, message);
282     vsnprintf(buf, sizeof(buf), fmt, args);
283     va_end(args);
284     s = buf;
285     while (*s)
286     {
287     char c;
288     t = s;
289     s += strcspn(s, "\n");
290     c = *s;
291     *s = 0;
292     send_cmd(source, "NOTICE %s :%s", dest->nick, *t ? t : " ");
293     *s = c;
294     if (c)
295     s++;
296     }
297 michael 1194 }
298    
299    
300     /* Like notice_lang(), but replace %S by the source. This is an ugly hack
301     * to simplify letting help messages display the name of the pseudoclient
302     * that's sending them.
303     */
304 michael 1209 void
305     notice_help(const char *source, const User * dest, int message, ...)
306 michael 1194 {
307 michael 1209 va_list args;
308     char buf[4096], buf2[4096], outbuf[BUFSIZE];
309     char *s, *t;
310     const char *fmt;
311 michael 1194
312 michael 1209 if (!dest)
313     return;
314     fmt = getstring(dest->ngi, message);
315     if (!fmt)
316     return;
317     /* Some sprintf()'s eat %S or turn it into just S, so change all %S's
318     * into \1\1... we assume this doesn't occur anywhere else in the
319     * string. */
320     strbcpy(buf2, fmt);
321     strnrepl(buf2, sizeof(buf2), "%S", "\1\1");
322     va_start(args, message);
323     vsnprintf(buf, sizeof(buf), buf2, args);
324     va_end(args);
325     s = buf;
326     while (*s)
327     {
328     char c;
329     t = s;
330     s += strcspn(s, "\n");
331     c = *s;
332     *s = 0;
333     strbcpy(outbuf, t);
334     *s = c;
335     if (c)
336     s++;
337     strnrepl(outbuf, sizeof(outbuf), "\1\1", source);
338     send_cmd(source, "NOTICE %s :%s", dest->nick, *outbuf ? outbuf : " ");
339     }
340 michael 1194 }
341    
342     /*************************************************************************/
343    
344     /* Send a PRIVMSG from the given source to the given nick. */
345    
346 michael 1209 void
347     privmsg(const char *source, const char *dest, const char *fmt, ...)
348 michael 1194 {
349 michael 1209 va_list args;
350     char buf[BUFSIZE];
351 michael 1194
352 michael 1209 va_start(args, fmt);
353     vsnprintf(buf, sizeof(buf), fmt, args);
354     va_end(args);
355     send_cmd(source, "PRIVMSG %s :%s", dest, buf);
356 michael 1194 }
357    
358     /*************************************************************************/
359     /*************************************************************************/
360    
361     /* Handler for unimplemented functions. */
362    
363 michael 1209 static void
364     unimplemented(void)
365 michael 1194 {
366 michael 1209 fatal("send.c: No (or bad) protocol module loaded.");
367 michael 1194 }
368    
369     /*************************************************************************/
370    
371     /*
372     * Local variables:
373     * c-file-style: "stroustrup"
374     * c-file-offsets: ((case-label . *) (statement-case-intro . *))
375     * indent-tabs-mode: nil
376     * End:
377     *
378     * vim: expandtab shiftwidth=4:
379     */