first simple rxpd access check
[webgit] / src / rxpd_client.c
1 /*
2     rxpd_client.c - regex policy daemon, client library
3
4   Copyright (C)
5     2007, 2008,         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 <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <netdb.h>
30 #include <poll.h>
31
32 struct rxpd_client
33 {
34   char* address;
35   char* port;
36   struct addrinfo* ai;
37
38   char* prefix;
39   FILE* handle;
40   char buf[4096];
41 };
42 typedef struct rxpd_client* RxpdClient;
43
44 /*
45   initialize a RxpdClient handle 'self'
46   'address' is the address of the rxpd to connect to,
47   either "host:port" for TCP or "path/to/socket" notation for unix domain sockets
48   'prefix' is the leading part for any list queried
49  */
50 RxpdClient
51 rxpd_client_init (RxpdClient self, const char* address, const char* prefix)
52 {
53   if (!self || !address)
54     return NULL;
55
56   self->handle = NULL;
57
58   self->address = strdup (address);
59   self->prefix = strdup (prefix);
60   if (!self->prefix || !self->address)
61     return NULL;
62
63   char* delim = strchr (self->address, ':');
64   if (delim)
65     {
66       /* TCP socket */
67       *delim = '\0';
68       self->port = delim+1;
69     }
70   else if (strchr (self->address, '/'))
71     {
72       /* unix domain socket */
73       self->port = NULL;
74       return NULL; /* TODO: rxpd doesnt yet support unix domain sockets */
75     }
76   else
77     {
78       /* syntax error */
79       return NULL;
80     }
81
82   /* resolve peer */
83   self->ai = NULL;
84   if (getaddrinfo (self->address, self->port, NULL, &self->ai))
85     return NULL;
86
87   return self;
88 }
89
90
91 /*
92   Destruct a rxpd_client structure
93  */
94 RxpdClient
95 rxpd_client_destroy (RxpdClient self)
96 {
97   if (self)
98     {
99       free (self->prefix);
100       free (self->address);
101       if (self->ai)
102         freeaddrinfo (self->ai);
103       if (self->handle)
104         fclose (self->handle);
105     }
106   return self;
107 }
108
109
110 /*
111   destruct and free a rxpd_client structure
112 */
113 void
114 rxpd_client_free (RxpdClient self)
115 {
116   free (rxpd_client_destroy (self));
117 }
118
119
120 /*
121   allocate and initialize a rxpd_client structure
122 */
123 RxpdClient
124 rxpd_client_new (const char* address, const char* prefix)
125 {
126   RxpdClient self = malloc (sizeof (struct rxpd_client));
127   if (!rxpd_client_init (self, address, prefix))
128     {
129       rxpd_client_free (self);
130       return NULL;
131     }
132   return self;
133 }
134
135
136 /*
137   open connection to rxpd if not already open
138  */
139 int
140 rxpd_client_open (RxpdClient self)
141 {
142   if (self && !self->handle)
143     {
144       int fd;
145       fd = socket (self->ai->ai_family, self->ai->ai_socktype, self->ai->ai_protocol);
146       if (fd == -1)
147         return 0;
148
149       if (connect (fd, self->ai->ai_addr, self->ai->ai_addrlen))
150         {
151           close (fd);
152           return 0;
153         }
154
155       self->handle = fdopen (fd, "rb+");
156       if (!self->handle)
157         {
158           close (fd);
159           return 0;
160         }
161
162       /* Local sockets not yet supported */
163     }
164   return 1;
165 }
166
167
168 /*
169   close connection when open
170  */
171 void
172 rxpd_client_close (RxpdClient self)
173 {
174   if (self->handle)
175     {
176       fclose (self->handle);
177       self->handle = NULL;
178     }
179 }
180
181
182 /*
183   send a command to the rxpd
184  */
185 int
186 rxpd_client_cmd (RxpdClient self, const char* command, const char* list)
187 {
188   if (!self || !rxpd_client_open (self))
189     return 0;
190
191   if (fprintf (self->handle, "%s:%s%s\n", command, self->prefix?self->prefix:"", list?list:"") < 0)
192     return 0;
193
194   fflush (self->handle);
195   return 1;
196 }
197
198
199 /*
200   send data to the rxpd
201 */
202 int
203 rxpd_client_query (RxpdClient self, const char* fmt, ...)
204 {
205   if (!self || !rxpd_client_open (self))
206     return 0;
207
208   va_list args;
209   int r;
210   va_start (args, fmt);
211   r = vfprintf (self->handle, fmt, args);
212   va_end (args);
213   if (r < 0)
214     return 0;
215
216   fflush (self->handle);
217   return 1;
218 }
219
220
221 /*
222   test if data is available for read from rxpd
223 */
224 int
225 rxpd_client_pending (RxpdClient self, int timeout)
226 {
227   if (!self || !self->handle)
228     return -1;
229
230   struct pollfd pollme;
231
232   pollme.fd = fileno (self->handle);
233   pollme.events = POLLIN;
234
235   return poll (&pollme, 1, timeout);
236 }
237
238
239 /*
240   read a response from rxpd
241
242   this call is blocking
243 */
244 const char*
245 rxpd_client_recieve (RxpdClient self)
246 {
247   if (!self->handle)
248     return NULL;
249   return fgets (self->buf, 4096, self->handle);
250 }
251
252
253 #ifdef RXPD_CLIENT_EXAMPLE
254 int
255 main ()
256 {
257   /* how to use */
258   RxpdClient query = rxpd_client_new ("galaxy:2345", "ct@pipapo.org/irc_experimental/");
259
260   if (rxpd_client_cmd (query, "CHECK", "xchat"))
261     {
262       const char* response;
263
264       rxpd_client_query (query, "TEST\n\n");
265
266       while (rxpd_client_pending (query, 1000))
267         {
268           response = rxpd_client_recieve (query);
269           printf ("> %s", response);
270         }
271     }
272   rxpd_client_free (query);
273
274   return 0;
275 }
276 #endif