ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/rpc/xml/rpc.C
Revision: 1.2
Committed: Wed Jul 25 01:33:46 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
updated MANIFEST and references to documentation

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