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