ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hybrid-ircservices-1/send.c
Revision: 1201
Committed: Mon Aug 22 18:55:33 2011 UTC (14 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 10669 byte(s)
Log Message:
- I decided to make the services 'hybrid only'. That said, I'm not
  going to continue the ircservices project in an official manner,
  since maintaining compatibility for a wide range of ircds would
  require an enormous amount of effort.

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