* Switched from bzero() to memset(), thanks Shaleh
[infodrom/cgilib] / cgi.c
1 /*
2     cgi.c - Some simple routines for cgi programming
3     Copyright (c) 1996-8  Martin Schulze <joey@infodrom.north.de>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <malloc.h>
26 #include <cgi.h>
27
28 int cgiDebugLevel = 0;
29 int cgiDebugStderr = 1;
30
31 void cgiHeader ()
32 {
33     printf ("Content-type: text/html\n\n");
34 }
35
36 void cgiDebug (int level, int where)
37 {
38     if (level > 0)
39         cgiDebugLevel = level;
40     else
41         cgiDebugLevel = 0;
42     if (where)
43         cgiDebugStderr = 0;
44     else
45         cgiDebugStderr = 1;
46 }
47
48 char *cgiDecodeString (char *text)
49 {
50     char *cp, *xp;
51
52     for (cp=text,xp=text; *cp; cp++) {
53         if (*cp == '%') {
54             if (strchr("0123456789ABCDEFabcdef", *(cp+1))
55                 && strchr("0123456789ABCDEFabcdef", *(cp+2))) {
56                 if (islower(*(cp+1)))
57                     *(cp+1) = toupper(*(cp+1));
58                 if (islower(*(cp+2)))
59                     *(cp+2) = toupper(*(cp+2));
60                 *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
61                     + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
62                 xp++;cp+=2;
63             }
64         } else {
65             *(xp++) = *cp;
66         }
67     }
68     memset(xp, 0, cp-xp);
69     return text;
70 }
71
72 /*  cgiInit()
73  *
74  *  Read from stdin if no string is provided via CGI.  Variables that
75  *  doesn't have a value associated with it doesn't get stored.
76  */
77 s_cgi **cgiInit ()
78 {
79     int length;
80     char *line = NULL;
81     int numargs;
82     char *cp, *ip, *esp, *sptr;
83     s_cgi **result;
84     int i, k;
85     char tmp[101];
86
87     cp = getenv("REQUEST_METHOD");
88     ip = getenv("CONTENT_LENGTH");
89
90     if (cp && !strcmp(cp, "POST")) {
91         if (ip) {
92             length = atoi(ip);
93             if ((line = (char *)malloc (length+2)) == NULL)
94                 return NULL;
95             fgets(line, length+1, stdin);
96         } else
97             return NULL;
98     } else if (cp && !strcmp(cp, "GET")) {
99         esp = getenv("QUERY_STRING");
100         if (esp && strlen(esp)) {
101             if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
102                 return NULL;
103             sprintf (line, "%s", esp);
104         } else
105             return NULL;
106     } else {
107         length = 0;
108         printf ("(offline mode: enter name=value pairs on standard input)\n");
109         for (cp = fgets(tmp, 100, stdin); cp != NULL;
110              cp = fgets(tmp, 100, stdin) ) {
111             if (strlen(tmp)) {
112                 length += strlen(tmp);
113                 if ((ip = (char *)malloc (length * sizeof(char))) == NULL)
114                     return NULL;
115                 memset(ip, 0, length);
116                 if (line) {
117                     if (line[strlen(line)-1] == '\n')
118                         line[strlen(line)-1] = '&';
119                     strcpy(ip, line);
120                 }
121                 ip = strcat(ip, tmp);
122                 if (line)
123                     free (line);
124                 line = ip;
125             }
126         }
127         if (!line)
128             return NULL;
129         if (line[strlen(line)-1] == '\n')
130             line[strlen(line)-1] = '\0';
131     }
132
133     /*
134      *  From now on all cgi variables are stored in the variable line
135      *  and look like  foo=bar&foobar=barfoo&foofoo=
136      */
137
138     if (cgiDebugLevel > 0)
139         if (cgiDebugStderr)
140             fprintf (stderr, "Received cgi input: %s\n", line);
141         else
142             printf ("<b>Received cgi input</b><br>\n<pre>\n--\n%s\n--\n</pre>\n\n", line);
143
144     for (cp=line; *cp; cp++)
145         if (*cp == '+')
146             *cp = ' ';
147
148     if (strlen(line)) {
149         for (numargs=1,cp=line; *cp; cp++)
150             if (*cp == '&') numargs++;
151     } else
152         numargs = 0;
153     if (cgiDebugLevel > 0)
154         if (cgiDebugStderr)
155             fprintf (stderr, "%d cgi variables found.\n", numargs);
156         else
157             printf ("%d cgi variables found.<br>\n", numargs);
158
159     if ((result = (s_cgi **)malloc((numargs+1) * sizeof(s_cgi *))) == NULL)
160         return NULL;
161     memset (result, 0, (numargs+1) * sizeof(s_cgi *));
162
163     cp = line;
164     i=0;
165     while (*cp) {
166         if ((ip = (char *)index(cp, '&')) != NULL) {
167             *ip = '\0';
168         }else
169             ip = cp + strlen(cp);
170
171         if ((esp=(char *)index(cp, '=')) == NULL) {
172             cp = ++ip;
173             continue;
174         }
175
176         if (!strlen(esp)) {
177             cp = ++ip;
178             continue;
179         }
180
181         if (i<numargs) {
182
183             for (k=0; k<i && (strncmp(result[k]->name,cp, esp-cp)); k++);
184             /* try to find out if there's already such a variable */
185             if (k == i) {       /* No such variable yet */
186                 if ((result[i] = (s_cgi *)malloc(sizeof(s_cgi))) == NULL)
187                     return NULL;
188                 if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
189                     return NULL;
190                 memset (result[i]->name, 0, esp-cp+1);
191                 strncpy(result[i]->name, cp, esp-cp);
192                 cp = ++esp;
193                 if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
194                     return NULL;
195                 memset (result[i]->value, 0, ip-esp+1);
196                 strncpy(result[i]->value, cp, ip-esp);
197                 result[i]->value = cgiDecodeString(result[i]->value);
198                 if (cgiDebugLevel) {
199                     if (cgiDebugStderr)
200                         fprintf (stderr, "%s: %s\n", result[i]->name, result[i]->value);
201                     else
202                         printf ("<h3>Variable %s</h3>\n<pre>\n%s\n</pre>\n\n", result[i]->name, result[i]->value);
203                 }
204                 i++;
205             } else {    /* There is already such a name, suppose a mutiple field */
206                 if ((sptr = (char *)malloc((strlen(result[k]->value)+(ip-esp)+2)* sizeof(char))) == NULL)
207                     return NULL;
208                 memset (sptr, 0, strlen(result[k]->value)+(ip-esp)+2);
209                 sprintf (sptr, "%s\n", result[k]->value);
210                 cp = ++esp;
211                 strncat(sptr, cp, ip-esp);
212                 free(result[k]->value);
213                 result[k]->value = sptr;
214             }
215         }
216         cp = ++ip;
217     }
218     return result;
219 }
220
221 char *cgiGetValue(s_cgi **parms, const char *var)
222 {
223     int i;
224
225     if (parms)
226         for (i=0;parms[i]; i++)
227             if (!strcmp(var,parms[i]->name)) {
228                 if (cgiDebugLevel > 0)
229                     if (cgiDebugStderr)
230                         fprintf (stderr, "%s found as %s\n", var, parms[i]->value);
231                     else
232                         printf ("%s found as %s<br>\n", var, parms[i]->value);
233                 return parms[i]->value;
234             }
235     if (cgiDebugLevel)
236         if (cgiDebugStderr)
237             fprintf (stderr, "%s not found\n", var);
238         else
239             printf ("%s not found<br>\n", var);
240
241     return NULL;
242 }
243
244 void cgiRedirect (const char *url)
245 {
246     if (url && strlen(url)) {
247         printf ("Content-type: text/html\nContent-length: %d\n", 77+(strlen(url)*2));
248         printf ("Status: 302 Temporal Relocation\n");
249         printf ("Location: %s\n\n", url);
250         printf ("<html>\n<body>\nThe page has been moved to <a href=\"%s\">%s</a>\n</body>\n</html>\n", url, url);
251     }
252 }
253
254 /*
255  * Local variables:
256  *  c-indent-level: 4
257  *  c-basic-offset: 4
258  *  tab-width: 8
259  * End:
260  */