28f9a9159090299a80a58f504556b6e28cfba466
[cascardo/pubsub-bot.git] / status.c
1 /*
2  *  Copyright (C) 2009  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19
20 #include <glib.h>
21 #include <iksemel.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 static char * server = "vespa.holoscopio.com";
28 static char * username = "pubsub";
29 static char * password = "pubsub";
30 static char * pbservice = "pubsub.vespa.holoscopio.com";
31 static char * authed_jid = "vespa";
32
33 iks *
34 createiq (char *type, char *to, char *qnam, char *xmlns, iks **query)
35 {
36   static int id = 0;
37   char sid[32];;
38   iks *iq;
39   snprintf (sid, 32, "ps%d", id++);
40   iq = iks_new ("iq");
41   iks_insert_attrib (iq, "type", type);
42   iks_insert_attrib (iq, "to", to);
43   iks_insert_attrib (iq, "id", sid);
44   *query = iks_insert (iq, qnam);
45   iks_insert_attrib (*query, "xmlns", xmlns);
46   return iq;
47 }
48
49 void
50 catnode (iksparser *parser, char *node)
51 {
52   iks *iq;
53   iks *query;
54   iq = createiq ("get", pbservice, "query",
55                  "http://jabber.org/protocol/disco#info", &query);
56   if (node != NULL)
57     iks_insert_attrib (query, "node", node);
58   iks_send (parser, iq);
59   iks_delete (iq);
60 }
61
62 void
63 listnode (iksparser *parser, char *node)
64 {
65   iks *iq;
66   iks *query;
67   iq = createiq ("get", pbservice, "query",
68                  "http://jabber.org/protocol/disco#items", &query);
69   if (node != NULL)
70     iks_insert_attrib (query, "node", node);
71   iks_send (parser, iq);
72   iks_delete (iq);
73 }
74
75 void
76 createnode (iksparser *parser, char *node)
77 {
78   iks *iq;
79   iks *query;
80   iq = createiq ("set", pbservice, "pubsub",
81                  "http://jabber.org/protocol/pubsub", &query);
82   iks_insert_attrib (iks_insert (query, "create"), "node", node);
83   iks_send (parser, iq);
84   iks_delete (iq);
85 }
86
87 void
88 getnode (iksparser *parser, char *node)
89 {
90   iks *iq;
91   iks *query;
92   iq = createiq ("get", pbservice, "pubsub",
93                  "http://jabber.org/protocol/pubsub", &query);
94   iks_insert_attrib (iks_insert (query, "items"), "node", node);
95   iks_send (parser, iq);
96   iks_delete (iq);
97 }
98
99 void
100 vcard (iksparser *parser)
101 {
102   iks *iq;
103   iks *query;
104   iq = createiq ("get", pbservice, "vCard", "vcard-temp", &query);
105   iks_send (parser, iq);
106   iks_delete (iq);
107 }
108
109 iks *
110 createmood (char *line)
111 {
112   iks *mood;
113   mood = iks_new ("mood");
114   iks_insert_attrib (mood, "xmlns", "http://jabber.org/protocol/mood");
115   iks_insert (mood, line);
116   return mood;
117 }
118
119 void
120 pushmood (iksparser *parser, char *node, char *line)
121 {
122   iks *iq;
123   iks *query;
124   iks *publish;
125   iks *item;
126   iks *mood;
127   iq = createiq ("set", pbservice, "pubsub",
128                  "http://jabber.org/protocol/pubsub", &query);
129   publish = iks_insert (query, "publish");
130   iks_insert_attrib (publish, "node", node);
131   item = iks_insert (publish, "item");
132   mood = createmood (line);
133   iks_insert_node (item, mood);
134   iks_send (parser, iq);
135   iks_delete (iq);
136 }
137
138 iks *
139 createtune (char *line)
140 {
141   iks *tune;
142   tune = iks_new ("tune");
143   iks_insert_attrib (tune, "xmlns", "http://jabber.org/protocol/tune");
144   iks_insert_cdata (iks_insert (tune, "artist"), line, 0);
145   return tune;
146 }
147
148 void
149 pushtune (iksparser *parser, char *node, char *line)
150 {
151   iks *iq;
152   iks *query;
153   iks *publish;
154   iks *item;
155   iks *tune;
156   iq = createiq ("set", pbservice, "pubsub",
157                  "http://jabber.org/protocol/pubsub", &query);
158   publish = iks_insert (query, "publish");
159   iks_insert_attrib (publish, "node", node);
160   item = iks_insert (publish, "item");
161   tune = createtune (line);
162   iks_insert_node (item, tune);
163   printf ("debug: %s\n", iks_string (iks_stack (iq), iq));
164   iks_send (parser, iq);
165   iks_delete (iq);
166 }
167
168
169 void
170 process_mood (iksparser *parser, char *cmdline)
171 {
172   char *cmd;
173   char *orig_cmdline;
174   orig_cmdline = cmdline = strdup (cmdline);
175   cmd = strsep (&cmdline, " ");
176   if (!strcmp (cmd, "ls"))
177     listnode (parser, cmdline);
178   else if (!strcmp (cmd, "cat"))
179     catnode (parser, cmdline);
180   else if (!strcmp (cmd, "vcard"))
181     vcard (parser);
182   else if (!strcmp (cmd, "create"))
183     createnode (parser, cmdline);
184   else if (!strcmp (cmd, "get"))
185     getnode (parser, cmdline);
186   else if (!strcmp (cmd, "mood"))
187     {
188       char *node;
189       node = "http://jabber.org/protocol/mood";
190       pushmood (parser, node, cmdline);
191     }
192   else if (!strcmp (cmd, "tune"))
193     {
194       char *node;
195       node = "http://jabber.org/protocol/tune";
196       pushtune (parser, node, cmdline);
197     }
198   free (orig_cmdline);
199 }
200
201 int
202 xmpp_session_hook (iksparser *parser, iks *node)
203 {
204   iks *iq;
205   iq = iks_new ("iq");
206   iks_insert_attrib (iq, "type", "set");
207   iks_insert_attrib (iq, "id", "session1");
208   iks_insert_attrib (iks_insert (iq, "session"),
209                      "xmlns", "urn:ietf:params:xml:ns:xmpp-session");
210   iks_send (parser, iq);
211   iks_delete (iq);
212   return 0;
213 }
214
215 int
216 xmpp_initial_presence_hook (iksparser *parser, iks *node)
217 {
218   iks *pres;
219   pres = iks_make_pres (IKS_SHOW_AVAILABLE, "Microblogging here!");
220   iks_send (parser, pres);
221   iks_delete (pres);
222   return 0;
223 }
224
225 int
226 xmpp_id_hook (iksparser *parser, iks *node, char *id)
227 {
228   if (!iks_strcmp (id, "bind1"))
229     {
230       xmpp_session_hook (parser, node);
231       return 0;
232     }
233   else if (!iks_strcmp (id, "session1"))
234     {
235       xmpp_initial_presence_hook (parser, node);
236       return 0;
237     }
238   else if (!iks_strncmp (id, "ps", 2))
239     {
240       printf ("%s\n", iks_string (iks_stack (node), node));
241     }
242   return 1;
243 }
244
245 int
246 xmpp_ns_hook (iksparser *parser, iks *node, char *ns)
247 {
248   return 1;
249 }
250
251 int
252 xmpp_iq_error (iksparser *parser, iks *node)
253 {
254   iks *enode;
255   char *to;
256   char *from;
257   if (!iks_strcmp (iks_find_attrib (node, "type"), "error"))
258     return 1;
259   to = iks_find_attrib (node, "to");
260   from = iks_find_attrib (node, "from");
261   if (to)
262     iks_insert_attrib (node, "from", to);
263   else
264     iks_insert_attrib (node, "from", NULL);
265   if (from)
266     iks_insert_attrib (node, "to", from);
267   else
268     iks_insert_attrib (node, "to", NULL);
269   iks_insert_attrib (node, "type", "error");
270   enode = iks_insert (node, "error");
271   iks_insert_attrib (enode, "type", "cancel");
272   iks_insert_attrib (iks_insert (enode, "feature-not-implemented"),
273                      "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
274   iks_send (parser, node);
275   return 0;
276 }
277
278 int
279 xmpp_tls_hook (iksparser *parser, iks *node)
280 {
281   iks_start_tls (parser);
282   return 0;
283 }
284
285 int
286 xmpp_sasl_hook (iksparser *parser, iks* node)
287 {
288   iks_start_sasl (parser, IKS_SASL_DIGEST_MD5, username, password);
289   return 0;
290 }
291
292 int
293 xmpp_bind_hook (iksparser *parser, iks *node)
294 {
295   iks *iq;
296   iq = iks_new ("iq");
297   iks_insert_attrib (iq, "type", "set");
298   iks_insert_attrib (iq, "id", "bind1");
299   iks_insert_attrib (iks_insert (iq, "bind"),
300                      "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
301   iks_send (parser, iq);
302   iks_delete (iq);
303   return 0;
304 }
305
306 int
307 xmpp_features_hook (iksparser *parser, iks *node)
308 {
309   iks *feat;
310   char *ns;
311   for (feat = iks_child (node); feat != NULL; feat = iks_next (feat))
312     {
313       ns = iks_find_attrib (feat, "xmlns");
314       if (!iks_strcmp (ns, "urn:ietf:params:xml:ns:xmpp-tls"))
315         {
316           xmpp_tls_hook (parser, node);
317           return 0;
318         }
319       else if (!iks_strcmp (ns, "urn:ietf:params:xml:ns:xmpp-sasl"))
320         {
321           xmpp_sasl_hook (parser, node);
322           return 0;
323         }
324       else if (!iks_strcmp (ns, "urn:ietf:params:xml:ns:xmpp-bind"))
325         {
326           xmpp_bind_hook (parser, node);
327           return 0;
328         }
329     }
330   return 1;
331 }
332
333 int
334 xmpp_other_hook (iksparser *parser, iks *node, char *ns)
335 {
336   if (!iks_strcmp (ns, "urn:ietf:params:xml:ns:xmpp-sasl"))
337     {
338       if (!iks_strcmp (iks_name (node), "success"))
339         iks_send_header (parser, server);
340       else if (!iks_strcmp (iks_name (node), "failure"))
341         printf ("failture to authenticate: %s\n",
342                 iks_string (iks_stack (node), node));
343       return 0;
344     }
345   return 1;
346 }
347
348
349 static int
350 hook (void *data, int type, iks *node)
351 {
352   char *name;
353   char *id;
354   char *ns;
355   char *iqns;
356   iksparser *parser;
357   parser = *(iksparser **) data;
358   name = iks_name (node);
359   id = iks_find_attrib (node, "id");
360   ns = iks_find_attrib (node, "xmlns"); 
361   iqns = iks_find_attrib (iks_child (node), "xmlns"); 
362   if (!iks_strcmp (name, "message"))
363     {
364       char *from;
365       from = iks_find_attrib (node, "from");
366       if (!iks_strncmp (from, authed_jid, iks_strlen (authed_jid)))
367         {
368           char *body = iks_find_cdata (node, "body");
369           if (body != NULL)
370             process_mood (parser, body);
371         }
372       else
373         {
374           printf ("%s is not authorized\n", from);
375         }
376       return IKS_OK;
377     }
378   else if (!iks_strcmp (name, "presence"))
379     {
380       char *from;
381       from = iks_find_attrib (node, "from");
382       printf ("I sense a disturbance in the force: %s!\n", from);
383     }
384   else if (!iks_strcmp (name, "iq"))
385     {
386       if (xmpp_id_hook (parser, node, id) == 0)
387         return IKS_OK;
388       if (xmpp_ns_hook (parser, node, iqns) == 0)
389         return IKS_OK;
390       xmpp_iq_error (parser, node);
391     }
392   else if (!iks_strcmp (name, "stream:features"))
393     {
394       if (xmpp_features_hook (parser, node) == 0)
395         return IKS_OK;
396     }
397   else if (!iks_strcmp (name, "stream:error"))
398     {
399       printf ("streamerror: %s\n", iks_string (iks_stack (node), node));
400     }
401   else
402     {
403       if (xmpp_other_hook (parser, node, ns) == 0)
404         return IKS_OK;
405       printf ("No no: %s\n", name);
406     }
407   return IKS_OK;
408 }
409
410 gboolean
411 handler (GIOChannel *channel, GIOCondition cond, gpointer data)
412 {
413   iksparser *parser = data;
414   iks_recv (parser, 0);
415   return TRUE;
416 }
417
418 void
419 loop (iksparser *parser)
420 {
421   GIOChannel *channel;
422   channel = g_io_channel_unix_new (iks_fd (parser));
423   g_io_add_watch (channel, G_IO_IN, handler, parser);
424   g_main_loop_run (g_main_loop_new (g_main_context_default (), TRUE));
425 }
426
427 int
428 main (int argc, char **argv)
429 {
430   iksparser *parser;
431   int c;
432   while ((c = getopt (argc, argv, "s:u:p:i:a:")) != -1)
433     {
434       switch (c)
435         {
436         case 's':
437           server = optarg;
438           break;
439         case 'u':
440           username = optarg;
441           break;
442         case 'p':
443           password = optarg;
444           break;
445         case 'i':
446           pbservice = optarg;
447           break;
448         case 'a':
449           authed_jid = optarg;
450           break;
451         }
452     }
453   parser = iks_stream_new ("jabber:client", &parser, hook);
454   iks_connect_tcp (parser, server, 5222);
455   loop (parser);
456   return 0;
457 }