handlr.c - geomyidae - A small C-based gopherd.
HTML git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/geomyidae/
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR README
DIR LICENSE
---
handlr.c (5663B)
---
1 /*
2 * Copy me if you can.
3 * by 20h
4 */
5
6 #include <unistd.h>
7 #include <memory.h>
8 #include <netdb.h>
9 #include <netinet/in.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <dirent.h>
18 #include <sys/wait.h>
19 #include <errno.h>
20 #include <libgen.h>
21
22 #include "ind.h"
23 #include "arg.h"
24
25 void
26 handledir(int sock, char *path, char *port, char *base, char *args,
27 char *sear, char *ohost, char *chost, char *bhost, int istls,
28 char *sel, char *traverse)
29 {
30 char *pa, *file, *e, *par;
31 struct dirent **dirent;
32 int ndir, i, ret = 0;
33 struct stat st;
34 filetype *type;
35
36 USED(args);
37 USED(sear);
38 USED(bhost);
39 USED(sel);
40 USED(traverse);
41
42 pa = xstrdup(path);
43
44 /* Is there any directory below the request? */
45 if (strlen(pa+strlen(base)) > 1) {
46 par = xstrdup(pa+strlen(base));
47 e = strrchr(par, '/');
48 *e = '\0';
49 dprintf(sock, "1..\t%s\t%s\t%s\r\n",
50 par, ohost, port);
51 free(par);
52 }
53
54 ndir = scandir(pa, &dirent, 0, alphasort);
55 if (ndir < 0) {
56 perror("scandir");
57 free(pa);
58 return;
59 } else {
60 for (i = 0; i < ndir && ret >= 0; i++) {
61 if (dirent[i]->d_name[0] == '.')
62 continue;
63
64 type = gettype(dirent[i]->d_name);
65
66 file = smprintf("%s%s%s",
67 pa,
68 pa[strlen(pa)-1] == '/'? "" : "/",
69 dirent[i]->d_name);
70 if (stat(file, &st) >= 0 && S_ISDIR(st.st_mode))
71 type = gettype("index.gph");
72 ret = dprintf(sock,
73 "%c%-50.50s %10s %16s\t%s\t%s\t%s\r\n",
74 *type->type,
75 dirent[i]->d_name,
76 humansize(st.st_size),
77 humantime(&(st.st_mtime)),
78 file + strlen(base), ohost, port);
79 free(file);
80 }
81 for (i = 0; i < ndir; i++)
82 free(dirent[i]);
83 free(dirent);
84 }
85 dprintf(sock, ".\r\n");
86
87 free(pa);
88 }
89
90 void
91 handlegph(int sock, char *file, char *port, char *base, char *args,
92 char *sear, char *ohost, char *chost, char *bhost, int istls,
93 char *sel, char *traverse)
94 {
95 gphindex *act;
96 int i, ret = 0;
97
98 USED(args);
99 USED(sear);
100 USED(bhost);
101 USED(sel);
102 USED(traverse);
103
104 act = gph_scanfile(file);
105 if (act != NULL) {
106 for (i = 0; i < act->num && ret >= 0; i++)
107 ret = gph_printelem(sock, act->n[i], file, base, ohost, port);
108 dprintf(sock, ".\r\n");
109
110 for (i = 0; i < act->num; i++) {
111 gph_freeelem(act->n[i]);
112 act->n[i] = NULL;
113 }
114 gph_freeindex(act);
115 }
116 }
117
118 void
119 handlebin(int sock, char *file, char *port, char *base, char *args,
120 char *sear, char *ohost, char *chost, char *bhost, int istls,
121 char *sel, char *traverse)
122 {
123 int fd;
124
125 USED(port);
126 USED(base);
127 USED(args);
128 USED(sear);
129 USED(ohost);
130 USED(bhost);
131 USED(sel);
132 USED(traverse);
133
134 fd = open(file, O_RDONLY);
135 if (fd >= 0) {
136 if (xsendfile(fd, sock) < 0)
137 perror("sendfile");
138 close(fd);
139 }
140 }
141
142 /*
143 * See RFC3875 5 NPH Scripts
144 *
145 * In gopher, with no header parsing, this allows bi-directional
146 * long-running communications. One example would be raw HTTP emulation.
147 */
148 void
149 handlecgi(int sock, char *file, char *port, char *base, char *args,
150 char *sear, char *ohost, char *chost, char *bhost, int istls,
151 char *sel, char *traverse)
152 {
153 char *script, *path, *filec, *scriptc;
154
155 USED(base);
156 USED(port);
157
158 filec = xstrdup(file);
159 scriptc = xstrdup(file);
160 path = dirname(filec);
161 script = basename(scriptc);
162
163 if (sear == NULL)
164 sear = "";
165 if (args == NULL)
166 args = "";
167
168 while (dup2(sock, 0) < 0 && errno == EINTR);
169 while (dup2(sock, 1) < 0 && errno == EINTR);
170 while (dup2(sock, 2) < 0 && errno == EINTR);
171 switch (fork()) {
172 case 0:
173 if (path != NULL) {
174 if (chdir(path) < 0)
175 break;
176 }
177
178 setcgienviron(script, file, port, base, args, sear, ohost, chost,
179 bhost, istls, sel, traverse);
180
181 if (execl(file, script, sear, args, ohost, port, traverse, sel,
182 (char *)NULL) == -1) {
183 perror("execl");
184 _exit(1);
185 }
186 case -1:
187 perror("fork");
188 break;
189 default:
190 wait(NULL);
191 free(filec);
192 free(scriptc);
193 break;
194 }
195 }
196
197 /*
198 * This is RFC3875 NPH Scripts
199 * plus parsing of GPH syntax for easier gophermap portability.
200 */
201 void
202 handledcgi(int sock, char *file, char *port, char *base, char *args,
203 char *sear, char *ohost, char *chost, char *bhost, int istls,
204 char *sel, char *traverse)
205 {
206 FILE *fp;
207 char *script, *path, *filec, *scriptc, *ln = NULL;
208 size_t linesiz = 0;
209 ssize_t n;
210 int outsocks[2], ret = 0;
211 gphelem *el;
212
213 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, outsocks) < 0)
214 return;
215
216 filec = xstrdup(file);
217 scriptc = xstrdup(file);
218 path = dirname(filec);
219 script = basename(scriptc);
220
221 if (sear == NULL)
222 sear = "";
223 if (args == NULL)
224 args = "";
225
226 while (dup2(sock, 0) < 0 && errno == EINTR);
227 while (dup2(sock, 2) < 0 && errno == EINTR);
228 switch (fork()) {
229 case 0:
230 while (dup2(outsocks[1], 1) < 0 && errno == EINTR);
231 close(outsocks[0]);
232 if (path != NULL) {
233 if (chdir(path) < 0)
234 break;
235 }
236
237 setcgienviron(script, file, port, base, args, sear, ohost, chost,
238 bhost, istls, sel, traverse);
239
240 if (execl(file, script, sear, args, ohost, port, traverse, sel,
241 (char *)NULL) == -1) {
242 perror("execl");
243 _exit(1);
244 }
245 break;
246 case -1:
247 perror("fork");
248 break;
249 default:
250 while (dup2(sock, 1) < 0 && errno == EINTR);
251 close(outsocks[1]);
252
253 if (!(fp = fdopen(outsocks[0], "r"))) {
254 perror("fdopen");
255 close(outsocks[0]);
256 break;
257 }
258
259 while ((n = getline(&ln, &linesiz, fp)) > 0 && ret >= 0) {
260 if (ln[n - 1] == '\n')
261 ln[--n] = '\0';
262
263 el = gph_getadv(ln);
264 if (el == NULL)
265 continue;
266
267 ret = gph_printelem(sock, el, file, base, ohost, port);
268 gph_freeelem(el);
269 }
270 if (ferror(fp))
271 perror("getline");
272 dprintf(sock, ".\r\n");
273
274 free(ln);
275 fclose(fp);
276 wait(NULL);
277 free(filec);
278 free(scriptc);
279 break;
280 }
281 }
282