ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/rpc/xml/rpc.C
Revision: 1.6
Committed: Sun Sep 16 18:54:44 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +8 -1 lines
Log Message:
#defines to enum

File Contents

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