use C stdio streams for sockets
[rxpd] / contrib / irc / xchat / rx.c
1 /*
2     rx.c - rxpd plugin for xchat
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 //#include <sys/resource.h>
29 #include <netinet/in.h>
30 //#include <arpa/inet.h>
31 //#include <fcntl.h>
32 //#include <time.h>
33 #include <netdb.h>
34 #include <sys/uio.h>
35
36 #include "xchat-plugin.h"
37
38 #define PNAME "RxpdPlugin"
39 #define PDESC "Uses rxpd to act on content";
40 #define PVERSION "0.1"
41
42 #define PREFIXCMP(str, pfx) (!strncmp (str, (pfx), sizeof (pfx)-1))
43
44 static xchat_plugin *ph;   /* plugin handle */
45
46 static struct rx_plugin_data
47 {
48   int debug;
49   const char* server;
50   const char* port;
51   const char* prefix;
52   const char* list;
53   struct addrinfo* addrs;
54   FILE* rxpd;
55 } rx_private;
56
57
58 void
59 xchat_plugin_get_info (char **name,
60                        char **desc,
61                        char **version,
62                        void **reserved)
63 {
64    *name = PNAME;
65    *desc = PDESC;
66    *version = PVERSION;
67 }
68
69 static int
70 rxstart_cb (char *word[], char *word_eol[], void *userdata)
71 {
72   struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
73
74   if (rx->rxpd)
75     {
76       xchat_printf (ph, "RX: already connected");
77       return XCHAT_EAT_ALL;
78     }
79
80   rx->server = strdup (word[2]);
81   rx->port = strdup (word[3]);
82   rx->list = strdup (word[4]);
83
84   int aierr;
85
86   /* resolve peer */
87   aierr = getaddrinfo (rx->server, rx->port, NULL, &rx->addrs);
88   if (aierr)
89     {
90       xchat_printf (ph, "could not resolve %s:%s, %s\n", rx->server, rx->port, gai_strerror (aierr));
91       return XCHAT_EAT_ALL;
92     }
93
94   int fd;
95
96   fd = socket (rx->addrs->ai_family, rx->addrs->ai_socktype, rx->addrs->ai_protocol);
97   if (fd == -1 || connect (fd, rx->addrs->ai_addr, rx->addrs->ai_addrlen))
98     {
99       freeaddrinfo (rx->addrs);
100       rx->addrs = NULL;
101       xchat_printf (ph, "error connecting %s:%s, %s\n", rx->server, rx->port, strerror (errno));
102       return XCHAT_EAT_ALL;
103     }
104
105   rx->rxpd = fdopen (fd, "rb+");
106   if (!rx->rxpd)
107     {
108       freeaddrinfo (rx->addrs);
109       rx->addrs = NULL;
110       xchat_printf (ph, "error connecting %s:%s, %s\n", rx->server, rx->port, strerror (errno));
111       return XCHAT_EAT_ALL;
112     }
113
114   fprintf (rx->rxpd, "CHECK:%s\n", rx->list);
115   /*error handling here*/
116
117   xchat_printf (ph, "established rxpd connection to %s:%s\n", rx->server, rx->port);
118
119   return XCHAT_EAT_ALL;
120 }
121
122 static int
123 rxstop_cb (char *word[], char *word_eol[], void *userdata)
124 {
125   struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
126
127   if (rx->rxpd)
128     {
129       fclose (rx->rxpd);
130       rx->rxpd = NULL;
131       freeaddrinfo (rx->addrs);
132       rx->addrs = NULL;
133       xchat_printf (ph, "closed rxpd connection to %s:%s\n", rx->server, rx->port);
134     }
135   else
136     xchat_printf (ph, "no rxpd connection established\n");
137
138   return XCHAT_EAT_ALL;
139 }
140
141 static int
142 rxadd_cb (char *word[], char *word_eol[], void *userdata)
143 {
144   //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
145   return XCHAT_EAT_ALL;   /* eat this command so xchat and other plugins can't process it */
146 }
147
148 static int
149 rxdel_cb (char *word[], char *word_eol[], void *userdata)
150 {
151   //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
152   return XCHAT_EAT_ALL;   /* eat this command so xchat and other plugins can't process it */
153 }
154
155 static int
156 rxlist_cb (char *word[], char *word_eol[], void *userdata)
157 {
158   //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
159   return XCHAT_EAT_ALL;   /* eat this command so xchat and other plugins can't process it */
160 }
161
162 static int
163 rxraw_cb (char *word[], char *word_eol[], void *userdata)
164 {
165   //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
166   return XCHAT_EAT_ALL;   /* eat this command so xchat and other plugins can't process it */
167 }
168
169 static int
170 rxdebug_cb (char *word[], char *word_eol[], void *userdata)
171 {
172   struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
173   rx->debug ^= 1;
174   xchat_printf (ph, "Turned rxpd debugging %s\n", rx->debug?"on":"off");  
175   return XCHAT_EAT_ALL;
176 }
177
178 static int
179 rxinfo_cb (char *word[], char *word_eol[], void *userdata)
180 {
181   struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
182   xchat_printf (ph, "RX: debugging is %s\n", rx->debug?"on":"off");  
183   if (rx->rxpd)
184     {
185       xchat_printf (ph, "RX: connected to %s:%s\n", rx->server, rx->port);  
186       xchat_printf (ph, "RX: using list %s\n", rx->list);
187     }
188   else
189     xchat_printf (ph, "RX: not connected\n");  
190
191   return XCHAT_EAT_ALL;
192 }
193
194 static int
195 rxhook_cb (char *word[], char *word_eol[], void *userdata)
196 {
197   struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
198
199   if (rx->rxpd)
200     {
201       /* ok do the checking*/
202       fprintf (rx->rxpd, "%s\n", word_eol[1]);
203
204       // TODO xchat_printf (ph, "RXPD: error writing\n");
205
206       char buffer[4096];
207
208       fgets (buffer, 4095, rx->rxpd);
209       /*todo error handling*/
210
211       char* nl = strrchr(buffer, '\n');
212       if (nl)
213         *nl = '\0';
214
215       if (rx->debug && !PREFIXCMP(buffer, "ok:"))
216         xchat_printf (ph, "RX: matched '%s'\n", buffer);
217
218       if (PREFIXCMP(buffer, "ignore:"))
219         return XCHAT_EAT_XCHAT;
220       //else if (PREFIXCMP(line, "kick:"))
221       //else if (PREFIXCMP(line, "kickban:"))
222       //else if (PREFIXCMP(line, "ban:"))
223       //else if (PREFIXCMP(line, "op:"))
224     }
225
226   return XCHAT_EAT_NONE;
227 }
228
229 static struct commands
230 {
231   const char* command;
232   const char* help;
233   int (*callback) (char *[], char *[], void *);
234 } command_table[] =
235   {
236     {"RXSTART", "Usage: RXSTART server port list; enables and connects to rxpd", rxstart_cb},
237     {"RXSTOP", "Usage: RXSTOP; disconnects and stops rxpd plugin", rxstop_cb},
238     {"RXADD", "Usage: RXADD listname rule; adds rule to list", rxadd_cb},
239     {"RXDEL", "Usage: RXDEL list rule; removes rule from list", rxdel_cb},
240     {"RXLIST", "Usage: RXLIST [list]; shows list", rxlist_cb},
241     //{"RXRAW", "Usage: RXRAW ...; sends a raw command to the rxpd", rxraw_cb},
242     {"RXDEBUG", "Usage: RXDEBUG; toggle rxpd plugin debugging", rxdebug_cb},
243     {"RXINFO", "Usage: RXINFO; show some information about the rxpd plugin", rxinfo_cb},
244     {NULL, NULL}
245   };
246
247
248 int
249 xchat_plugin_init (xchat_plugin *plugin_handle,
250                    char **plugin_name,
251                    char **plugin_desc,
252                    char **plugin_version,
253                    char *arg)
254 {
255   /* we need to save this for use with any xchat_* functions */
256   ph = plugin_handle;
257
258   /* tell xchat our info */
259   *plugin_name = PNAME;
260   *plugin_desc = PDESC;
261   *plugin_version = PVERSION;
262
263   rx_private.debug = 0;
264   rx_private.server = NULL;
265   rx_private.port = NULL;
266   rx_private.list = NULL;
267   rx_private.addrs = NULL;
268   rx_private.rxpd = NULL;
269
270   struct commands* itr;
271   for (itr = command_table; itr->command; ++itr)
272     xchat_hook_command (ph, itr->command, XCHAT_PRI_NORM, itr->callback,
273                         itr->help, &rx_private);
274
275   xchat_hook_server (ph, "RAW LINE", XCHAT_PRI_NORM, rxhook_cb, &rx_private);
276
277   xchat_print (ph, "Rxpd plugin loaded successfully!\n");
278
279   return 1;
280 }
281
282 int
283 xchat_plugin_deinit (void)
284 {
285   if (rx_private.rxpd)
286     fclose (rx_private.rxpd);
287
288   if (rx_private.addrs)
289     freeaddrinfo (rx_private.addrs);
290
291   xchat_printf (ph, "rxpd plugin unloaded\n");
292
293   return 1;
294