ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/rpc/xml/rpc.C
Revision: 1.4
Committed: Thu Aug 30 19:56:24 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +17 -15 lines
Log Message:
- put faultcodes into their own namespace
- removed old files
- limited header garbage in atheme.h
- macros to inline bools for connection_t::is_*
- put some connection_t functions into the connection_t class

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * XML RPC Library
3     *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Copyright © 2005 Trystan Scott Lee
6     * Contact trystan@nomadirc.net
7     *
8 pippijn 1.2 * Please read doc/poddoc/license.pod and README for further details.
9 pippijn 1.1 *
10     * Based on the original code from Denora
11     */
12    
13 pippijn 1.4 #include <common/dynbuf.h>
14    
15 pippijn 1.1 #include "xml/rpc.h"
16    
17     int xmlrpc_error_code;
18    
19     xmlrpc_cmdhash *xmlrpc_cmds[MAX_CMD_HASH];
20    
21     xmlrpc_set xmlrpc;
22    
23     static char *xmlrpc_get_token (char const *str, char const dilim, int token_number);
24     static char *xmlrpc_get_token_remainder (char const *str, char const dilim, int token_number);
25     static char *xmlrpc_substr (char const *src, int start, int end);
26     static char *xmlrpc_parse (char *buffer);
27     static char *xmlrpc_method (char *buffer);
28     static char *xmlrpc_normalize_buffer (char *buf);
29     #ifndef HAVE_STRCASESTR
30     static char *strcasestr (char *s1, char *s2);
31     #endif
32     static int xmlrpc_split_buf (char *buffer, char ***argv);
33    
34     xmlrpc_cmd *create_xml_command (char const *name, XMLRPCMethodFunc func);
35     xmlrpc_cmd *find_xmlrpc_command (xmlrpc_cmdhash *hook_event_table[], char const *name);
36     int add_xml_command (xmlrpc_cmdhash *hook_event_table[], xmlrpc_cmd *xml);
37     int destroy_xmlrpc_command (xmlrpc_cmd *xml);
38    
39     /*************************************************************************/
40    
41     void
42     xmlrpc_process (char *buffer, void *userdata)
43     {
44     int retVal = 0;
45     xmlrpc_cmd *current = NULL;
46     xmlrpc_cmd *xml;
47     char *tmp;
48     int ac = 0;
49     char **av;
50     char *name = NULL;
51    
52     xmlrpc_error_code = 0;
53    
54     if (!buffer)
55     {
56     xmlrpc_error_code = -1;
57     return;
58     }
59    
60     tmp = xmlrpc_parse (buffer);
61     if (tmp)
62     {
63     name = xmlrpc_method (tmp);
64     if (name)
65     {
66     xml = find_xmlrpc_command (xmlrpc_cmds, name);
67     if (xml)
68     {
69     ac = xmlrpc_split_buf (tmp, &av);
70     if (xml->func)
71     {
72     retVal = xml->func (userdata, ac, av);
73     if (retVal == XMLRPC_CONT)
74     {
75     current = xml->next;
76     while (current && current->func && retVal == XMLRPC_CONT)
77     {
78     retVal = current->func (userdata, ac, av);
79     current = current->next;
80     }
81     }
82     else
83     { /* we assume that XMLRPC_STOP means the handler has given no output */
84     xmlrpc_error_code = -7;
85     xmlrpc_generic_error (xmlrpc_error_code, "XMLRPC error: First eligible function returned XMLRPC_STOP");
86     }
87     }
88     else
89     {
90     xmlrpc_error_code = -6;
91     xmlrpc_generic_error (xmlrpc_error_code, "XMLRPC error: Method has no registered function");
92     }
93     }
94     else
95     {
96     xmlrpc_error_code = -4;
97     xmlrpc_generic_error (xmlrpc_error_code, "XMLRPC error: Unknown routine called");
98     }
99     }
100     else
101     {
102     xmlrpc_error_code = -3;
103     xmlrpc_generic_error (xmlrpc_error_code, "XMLRPC error: Missing methodRequest or methodName.");
104     }
105     }
106     else
107     {
108     xmlrpc_error_code = -2;
109     xmlrpc_generic_error (xmlrpc_error_code, "XMLRPC error: Invalid document end at line 1");
110     }
111    
112     if (ac)
113 pippijn 1.3 sfree (av);
114 pippijn 1.1
115     if (tmp)
116 pippijn 1.3 sfree (tmp);
117 pippijn 1.1
118     if (name)
119 pippijn 1.3 sfree (name);
120 pippijn 1.1 }
121    
122     /*************************************************************************/
123    
124     void
125     xmlrpc_set_buffer (char *(*func) (char *buffer, int len))
126     {
127     xmlrpc.setbuffer = func;
128     }
129    
130     /*************************************************************************/
131    
132     int
133     xmlrpc_register_method (char const *name, XMLRPCMethodFunc func)
134     {
135     xmlrpc_cmd *xml;
136     xml = create_xml_command (name, func);
137     return add_xml_command (xmlrpc_cmds, xml);
138     }
139    
140     /*************************************************************************/
141    
142     xmlrpc_cmd *
143     create_xml_command (char const *name, XMLRPCMethodFunc func)
144     {
145     xmlrpc_cmd *xml = new xmlrpc_cmd;
146     xml->name = sstrdup (name);
147     xml->func = func;
148     xml->next = NULL;
149     return xml;
150     }
151    
152     /*************************************************************************/
153    
154     xmlrpc_cmd *
155     find_xmlrpc_command (xmlrpc_cmdhash *hook_event_table[], char const *name)
156     {
157     int idx;
158     xmlrpc_cmdhash *current = NULL;
159     if (!hook_event_table || !name)
160     return NULL;
161     idx = gen_cmd_hash (name);
162    
163     for (current = hook_event_table[idx]; current; current = current->next)
164     if (stricmp (name, current->name) == 0)
165     return current->xml;
166    
167     return NULL;
168     }
169    
170     /*************************************************************************/
171    
172     int
173     add_xml_command (xmlrpc_cmdhash *hook_event_table[], xmlrpc_cmd *xml)
174     {
175     /* We can assume both param's have been checked by this point.. */
176     int idx = 0;
177     xmlrpc_cmdhash *current = NULL;
178     xmlrpc_cmdhash *newHash = NULL;
179     xmlrpc_cmdhash *lastHash = NULL;
180    
181     if (!hook_event_table || !xml)
182     return XMLRPC_ERR_PARAMS;
183     idx = gen_cmd_hash (xml->name);
184    
185     for (current = hook_event_table[idx]; current; current = current->next)
186     {
187     if (stricmp (xml->name, current->name) == 0)
188     {
189     xml->next = current->xml;
190     current->xml = xml;
191     return XMLRPC_ERR_OK;
192     }
193     lastHash = current;
194     }
195    
196     if ((newHash = new xmlrpc_cmdhash) == NULL)
197     return XMLRPC_ERR_OK;
198     newHash->next = NULL;
199     newHash->name = sstrdup (xml->name);
200     newHash->xml = xml;
201    
202     if (lastHash == NULL)
203     hook_event_table[idx] = newHash;
204     else
205     lastHash->next = newHash;
206     return XMLRPC_ERR_OK;
207     }
208    
209     /*************************************************************************/
210    
211     int
212     xmlrpc_unregister_method (char const *method)
213     {
214     xmlrpc_cmd *xml;
215    
216     xml = find_xmlrpc_command (xmlrpc_cmds, method);
217     return destroy_xmlrpc_command (xml);
218     }
219    
220     /*************************************************************************/
221    
222     /**
223     * Destroy a command, freeing its memory.
224     *
225     * \param xml the command to be destroyed
226     *
227     * \return XMLRPC_ERR_OK on success
228     **/
229     int
230     destroy_xmlrpc_command (xmlrpc_cmd *xml)
231     {
232     if (xml->name)
233 pippijn 1.3 sfree (xml->name);
234 pippijn 1.1 xml->func = NULL;
235     xml->next = NULL;
236    
237     return XMLRPC_ERR_OK;
238     }
239    
240     /*************************************************************************/
241    
242     /**
243     * Parse Data down to just the <xml> without any \r\n or \t
244     * @param buffer Incoming data buffer
245     * @return cleaned up buffer
246     */
247     char *
248     xmlrpc_parse (char *buffer)
249     {
250     char *tmp = NULL;
251    
252     /*
253     * Okay since the buffer could contain
254     * HTTP header information, lets break
255     * off at the point that the <?xml?> starts
256     */
257 pippijn 1.3 tmp = strcasestr (buffer, const_cast<char *> ("<?xml"));
258 pippijn 1.1
259     /* check if its xml doc */
260     if (tmp)
261     /* get all the odd characters out of the data */
262     return xmlrpc_normalize_buffer (tmp);
263    
264     return NULL;
265     }
266    
267     /*************************************************************************/
268    
269     static int
270     xmlrpc_split_buf (char *buffer, char ***argv)
271     {
272     int ac = 0;
273     int argvsize = 8;
274     char *data, *str;
275     char *str2 = NULL;
276     char *nexttag = NULL;
277     char *temp = NULL;
278     char *final;
279     int tagtype = 0;
280    
281 pippijn 1.4 *argv = salloc<char *> (argvsize);
282 pippijn 1.1 while ((data = strstr (buffer, "<value>")))
283     {
284     if (data)
285     {
286     temp = xmlrpc_get_token (data, '<', 2);
287     nexttag = xmlrpc_get_token (temp, '>', 0);
288     /* strings */
289     if (!stricmp ("string", nexttag))
290     tagtype = 1;
291     else
292     tagtype = 0;
293     str = xmlrpc_get_token (data, '>', 2);
294     str2 = xmlrpc_get_token_remainder (data, '>', 2);
295     if (str)
296     {
297     final = xmlrpc_get_token (str, '<', 0);
298     if (final)
299     {
300     if (tagtype == 1)
301     (*argv)[ac++] = xmlrpc_decode_string (final);
302     else
303     (*argv)[ac++] = final;
304     }
305 pippijn 1.3 sfree (str);
306 pippijn 1.1 } /* str */
307     } /* data */
308     buffer = str2;
309     } /* while */
310    
311 pippijn 1.3 sfree (str2);
312 pippijn 1.1
313     return ac;
314     }
315    
316     /*************************************************************************/
317    
318     char *
319     xmlrpc_method (char *buffer)
320     {
321     char *data;
322     char *tmp, *tmp2;
323    
324 pippijn 1.3 data = strcasestr (buffer, const_cast<char *> ("<methodname>"));
325 pippijn 1.1 if (data)
326     {
327     tmp = xmlrpc_get_token (data, '>', 1);
328     tmp2 = xmlrpc_get_token (tmp, '<', 0);
329 pippijn 1.3 sfree (tmp);
330 pippijn 1.1 return tmp2;
331     }
332    
333     return NULL;
334     }
335    
336     /*************************************************************************/
337    
338     void
339     xmlrpc_generic_error (int code, char const *string)
340     {
341     char buf[XMLRPC_BUFSIZE];
342     int len;
343    
344     snprintf (buf, XMLRPC_BUFSIZE, "<?xml version=\"1.0\"?>\r\n"
345     "<methodResponse>\r\n"
346     " <fault>\r\n"
347     " <value>\r\n"
348     " <struct>\r\n"
349     " <member>\r\n"
350     " <name>faultCode</name>\r\n"
351     " <value><int>%d</int></value>\r\n" // code
352     " </member>\r\n"
353     " <member>\r\n"
354     " <name>faultString</name>\r\n"
355     " <value><string>%s</string></value>\r\n" // string
356     " </member>\r\n"
357     " </struct>\r\n"
358     " </value>\r\n"
359     " </fault>\r\n"
360     "</methodResponse>",
361     code, string);
362     len = strlen (buf);
363    
364     xmlrpc.setbuffer (buf, len);
365     }
366    
367     /*************************************************************************/
368    
369     void
370     xmlrpc_send (int argc, ...)
371     {
372     va_list va;
373     char *a;
374     int idx = 0;
375     char *s = NULL;
376     int len;
377     char buf[XMLRPC_BUFSIZE];
378     char buf2[XMLRPC_BUFSIZE];
379    
380     *buf = '\0';
381     *buf2 = '\0';
382    
383     va_start (va, argc);
384     for (idx = 0; idx < argc; idx++)
385     {
386     a = va_arg (va, char *);
387     if (expect_false (!s))
388     {
389     snprintf (buf, XMLRPC_BUFSIZE, " <param>\r\n"
390     " <value>\r\n"
391     " %s\r\n" // a
392     " </value>\r\n"
393     " </param>",
394     a);
395     s = sstrdup (buf);
396     }
397     else
398     {
399     snprintf (buf, XMLRPC_BUFSIZE, "%s\r\n" // s
400     " <param>\r\n"
401     " <value>\r\n"
402     " %s\r\n" // a
403     " </value>\r\n"
404     " </param>",
405     s, a);
406 pippijn 1.3 sfree (s);
407 pippijn 1.1 s = sstrdup (buf);
408     }
409     }
410     va_end (va);
411    
412     if (xmlrpc.encode)
413     snprintf (buf, XMLRPC_BUFSIZE, "<?xml version=\"1.0\" encoding=\"%s\"?>\r\n" // xmlrpc.encode
414     "<methodResponse>\r\n"
415     " <params>\r\n"
416     " %s\r\n" // s
417     " </params>\r\n"
418     "</methodResponse>",
419     xmlrpc.encode, s);
420     else
421     snprintf (buf, XMLRPC_BUFSIZE, "<?xml version=\"1.0\"?>\r\n"
422     "<methodResponse>\r\n"
423     " <params>\r\n"
424     " %s\r\n" // s
425     " </params>\r\n"
426     "</methodResponse>",
427     s);
428     len = strlen (buf);
429    
430     xmlrpc.setbuffer (buf, len);
431    
432     if (xmlrpc.encode)
433     {
434 pippijn 1.3 sfree (xmlrpc.encode);
435 pippijn 1.1 xmlrpc.encode = NULL;
436     }
437 pippijn 1.3 sfree (s);
438 pippijn 1.1 }
439    
440     /*************************************************************************/
441    
442     char *
443     xmlrpc_string (char *buf, char const *value)
444     {
445     char encoded[XMLRPC_BUFSIZE];
446     *buf = '\0';
447    
448     xmlrpc_char_encode (encoded, value);
449     snprintf (buf, XMLRPC_BUFSIZE, "<string>%s</string>", encoded);
450     return buf;
451     }
452    
453     /*************************************************************************/
454    
455     /**
456     * Get the token
457     * @param str String to search in
458     * @param dilim Character to search for
459     * @param token_number the token number
460     * @return token
461     */
462     static char *
463     xmlrpc_get_token (char const *str, char const dilim, int token_number)
464     {
465     int len, idx, counter = 0, start_pos = 0;
466     char *substring = NULL;
467     if (!str)
468     return NULL;
469    
470     len = strlen (str);
471    
472     for (idx = 0; idx <= len; idx++)
473     if ((str[idx] == dilim) || (idx == len))
474     {
475     if (counter == token_number)
476     {
477     substring = xmlrpc_substr (str, start_pos, idx);
478     counter++;
479     }
480     else
481     {
482     start_pos = idx + 1;
483     counter++;
484     }
485     }
486    
487     return substring;
488     }
489    
490     /*************************************************************************/
491    
492     /**
493     * Get the Remaining tokens
494     * @param str String to search in
495     * @param dilim Character to search for
496     * @param token_number the token number
497     * @return token
498     */
499     static char *
500     xmlrpc_get_token_remainder (char const *str, char const dilim, int token_number)
501     {
502     int len, idx, counter = 0, start_pos = 0;
503     char *substring = NULL;
504     if (!str)
505     return NULL;
506    
507     len = strlen (str);
508    
509     for (idx = 0; idx <= len; idx++)
510     if ((str[idx] == dilim) || (idx == len))
511     {
512     if (counter == token_number)
513     {
514     substring = xmlrpc_substr (str, start_pos, len);
515     counter++;
516     }
517     else
518     {
519     start_pos = idx + 1;
520     counter++;
521     }
522     }
523    
524     return substring;
525     }
526    
527     /*************************************************************************/
528    
529     /**
530     * Get the string between point A and point B
531     * @param str String to search in
532     * @param start Point A
533     * @param end Point B
534     * @return the string in between
535     */
536     static char *
537     xmlrpc_substr (char const *src, int start, int end)
538     {
539     char *substring = NULL;
540     int len, idx;
541    
542     if (!src)
543     return NULL;
544    
545     len = strlen (src);
546    
547     if (((start >= 0) && (end <= len)) && (end > start))
548     {
549 pippijn 1.4 substring = salloc<char> ((end - start) + 1);
550 pippijn 1.1 for (idx = 0; idx <= end - start; idx++)
551     substring[idx] = src[start + idx];
552     substring[end - start] = '\0';
553     }
554    
555     return substring;
556     }
557    
558     /*************************************************************************/
559    
560     char *
561     xmlrpc_normalize_buffer (char *buf)
562     {
563     char *newbuf;
564     int i, len, j = 0;
565    
566     len = strlen (buf);
567 pippijn 1.4 newbuf = salloc<char> (len + 1);
568 pippijn 1.1
569     for (i = 0; i < len; i++)
570     {
571     switch (buf[i])
572     {
573     /* ctrl char */
574     case 1:
575     break;
576     /* Bold ctrl char */
577     case 2:
578     break;
579     /* Color ctrl char */
580     case 3:
581     /* If the next character is a digit, its also removed */
582     if (isdigit (buf[i + 1]))
583     {
584     i++;
585    
586     /* not the best way to remove colors
587     * which are two digit but no worse then
588     * how the Unreal does with +S - TSL
589     */
590     if (isdigit (buf[i + 1]))
591     i++;
592    
593     /* Check for background color code
594     * and remove it as well
595     */
596     if (buf[i + 1] == ',')
597     {
598     i++;
599    
600     if (isdigit (buf[i + 1]))
601     i++;
602     /* not the best way to remove colors
603     * which are two digit but no worse then
604     * how the Unreal does with +S - TSL
605     */
606     if (isdigit (buf[i + 1]))
607     i++;
608     }
609     }
610    
611     break;
612     /* tabs char */
613     case 9:
614     break;
615     /* line feed char */
616     case 10:
617     break;
618     /* carrage returns char */
619     case 13:
620     break;
621     /* Reverse ctrl char */
622     case 22:
623     break;
624     /* Underline ctrl char */
625     case 31:
626     break;
627     /* A valid char gets copied into the new buffer */
628     default:
629     newbuf[j++] = buf[i];
630     }
631     }
632    
633     /* Terminate the string */
634     newbuf[j] = 0;
635    
636     return (newbuf);
637     }
638    
639     /*************************************************************************/
640    
641     #ifndef HAVE_STRCASESTR
642     char *
643     strcasestr (char *s1, char *s2)
644     {
645     register char *s = s1, *d = s2;
646    
647     while (*s1)
648     if (tolower (*s1) == tolower (*d))
649     {
650     s1++;
651     d++;
652     if (*d == 0)
653     return s;
654     }
655     else
656     {
657     s = ++s1;
658     d = s2;
659     }
660    
661     return NULL;
662     }
663     #endif
664    
665     /*************************************************************************/
666    
667     void
668     xmlrpc_char_encode (char *outbuffer, char const *s1)
669     {
670     unsigned char c;
671 pippijn 1.3 dynstr s (XMLRPC_BUFSIZE);
672 pippijn 1.1
673     *outbuffer = '\0';
674    
675     if ((!(s1) || (*(s1) == '\0')))
676     return;
677    
678     while ((c = *s1++))
679     {
680     if (c > 0x7f)
681 pippijn 1.4 {
682     char buf[15];
683     snprintf (buf, 15, "&#%c;", c);
684     s.add (buf);
685     }
686 pippijn 1.1 else if (c == '&')
687 pippijn 1.4 s.add ("&amp;");
688 pippijn 1.1 else if (c == '<')
689 pippijn 1.4 s.add ("&lt;");
690 pippijn 1.1 else if (c == '>')
691 pippijn 1.4 s.add ("&gt;");
692 pippijn 1.1 else if (c == '"')
693 pippijn 1.4 s.add ("&quot;");
694 pippijn 1.1 else
695 pippijn 1.4 s.add (c);
696 pippijn 1.1 }
697 pippijn 1.4
698 pippijn 1.1 memcpy (outbuffer, s.c_str (), XMLRPC_BUFSIZE);
699     }
700    
701     char *
702     xmlrpc_decode_string (char *buf)
703     {
704     int count;
705     int i;
706     char *token, *temp;
707 pippijn 1.4 char **tokens = salloc<char *> (128);
708 pippijn 1.1 char *temptoken;
709     char buf2[12];
710     char buf3[12];
711    
712     replace (buf, XMLRPC_BUFSIZE, "&gt;", ">");
713     replace (buf, XMLRPC_BUFSIZE, "&lt;", "<");
714     replace (buf, XMLRPC_BUFSIZE, "&quot;", "\"");
715     replace (buf, XMLRPC_BUFSIZE, "&amp;", "&");
716    
717     temp = sstrdup (buf);
718     count = sjtoken (temp, '&', tokens);
719    
720     for (i = 1; i < count; i++)
721     {
722     token = tokens[i];
723     if (token && *token == '#')
724     {
725     temptoken = strtok ((token + 1), ";");
726     snprintf (buf2, 12, "%c", atoi (temptoken));
727     snprintf (buf3, 12, "&%s;", token);
728     replace (buf, XMLRPC_BUFSIZE, buf3, buf2);
729     }
730     }
731    
732 pippijn 1.3 sfree (temp);
733 pippijn 1.1
734     return buf;
735     }