Subversion Repositories Keine

Rev

Rev 6 | Rev 8 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: cgi.c 7 2024-09-11 15:46:04Z nishi $ */
2
 
3
#include "../config.h"
4
 
5
#include "kn_cgi.h"
6
 
6 nishi 7
#include <dirent.h>
2 nishi 8
#include <stdlib.h>
9
#include <string.h>
10
#include <stdbool.h>
6 nishi 11
#include <sys/stat.h>
2 nishi 12
#include <stdio.h>
13
 
14
#include "kn_version.h"
15
#include "kn_util.h"
4 nishi 16
#include "kn_man.h"
2 nishi 17
 
18
struct q_entry {
19
	char* key;
20
	char* value;
21
};
22
 
23
bool no = false;
24
bool showmain = false;
25
struct q_entry** entries = NULL;
4 nishi 26
char* path;
2 nishi 27
 
4 nishi 28
char* kn_get_query(const char* key) {
2 nishi 29
	if(entries == NULL) return NULL;
30
	int i;
4 nishi 31
	for(i = 0; entries[i] != NULL; i++) {
32
		if(strcmp(entries[i]->key, key) == 0) return entries[i]->value;
2 nishi 33
	}
34
	return NULL;
35
}
36
 
4 nishi 37
char* kn_null(const char* a) { return a == NULL ? "" : (char*)a; }
2 nishi 38
 
6 nishi 39
void manpage_scan(const char* root) {
40
	struct dirent** nl;
41
	int n = scandir(root, &nl, NULL, alphasort);
42
	if(n < 0) return;
43
	int i;
44
	for(i = 0; i < n; i++) {
45
		if(strcmp(nl[i]->d_name, ".") != 0 && strcmp(nl[i]->d_name, "..") != 0) {
46
			char* path = kn_strcat3(root, "/", nl[i]->d_name);
47
			struct stat s;
48
			if(stat(path, &s) == 0) {
49
				if(S_ISDIR(s.st_mode)) {
50
					manpage_scan(path);
51
				} else {
52
					char* name = kn_strdup(nl[i]->d_name);
7 nishi 53
					char* desc = kn_strdup("&lt;No description detected&gt;");
6 nishi 54
 
55
					int incr = 0;
56
					FILE* f = fopen(path, "r");
57
					char* b = malloc(s.st_size + 1);
58
					b[s.st_size] = 0;
59
					fread(b, s.st_size, 1, f);
60
					fclose(f);
61
 
62
					int j;
7 nishi 63
					for(j = 0;; j++) {
64
						if(b[j] == '\n' || b[j] == 0) {
6 nishi 65
							char* line = malloc(j - incr + 1);
66
							line[j - incr] = 0;
67
							memcpy(line, b + incr, j - incr);
68
 
69
							int k;
7 nishi 70
							for(k = 0; line[k] != 0 && k < 4; k++) {
71
								if(line[k] == ' ') {
6 nishi 72
									line[k] = 0;
7 nishi 73
									if(strcasecmp(line, ".Nd") == 0) {
6 nishi 74
										free(desc);
75
										desc = kn_strdup(line + k + 1);
76
										int l;
7 nishi 77
										for(l = 0; desc[l] != 0; l++) {
78
											if(desc[l] == '\\') {
6 nishi 79
												l++;
7 nishi 80
												if(desc[l] == '"') {
6 nishi 81
													l--;
82
													desc[l] = 0;
83
													break;
84
												}
85
											}
86
										}
87
									}
88
									break;
89
								}
90
							}
91
 
92
							free(line);
93
							incr = j + 1;
94
							if(b[j] == 0) break;
95
						}
96
					}
97
 
98
					free(b);
99
 
7 nishi 100
					if(strlen(desc) > 70) {
6 nishi 101
						desc[70] = 0;
102
						desc[69] = '.';
103
						desc[68] = '.';
104
						desc[67] = '.';
105
					}
106
 
107
					printf("<tr>\n");
108
					printf("	<td><a href=\"?page=%s\">%s</a></td>\n", name, name);
109
					printf("	<td><code>%s</code></td>\n", desc);
110
					printf("</tr>\n");
111
 
112
					free(name);
113
					free(desc);
114
				}
115
			}
116
			free(path);
117
		}
118
		free(nl[i]);
119
	}
120
	free(nl);
121
}
122
 
123
void list_manpages(void) {
124
#ifdef MANPAGE_DIRS
125
	int i;
126
	const char* dirs[] = MANPAGE_DIRS;
7 nishi 127
	for(i = 0; i < sizeof(dirs) / sizeof(*dirs); i++) {
6 nishi 128
		manpage_scan(dirs[i]);
129
	}
130
#else
131
	manpage_scan(MANPAGE_DIR);
132
#endif
133
}
134
 
4 nishi 135
void kn_parse_query(void) {
2 nishi 136
	char* query = getenv("QUERY_STRING");
4 nishi 137
	if(query != NULL) {
2 nishi 138
		entries = malloc(sizeof(*entries));
139
		entries[0] = NULL;
140
		int i;
141
		int incr = 0;
4 nishi 142
		for(i = 0;; i++) {
143
			if(query[i] == 0 || query[i] == '&') {
2 nishi 144
				char* a = malloc(i - incr + 1);
4 nishi 145
				memcpy(a, query + incr, i - incr);
2 nishi 146
				a[i - incr] = 0;
147
 
148
				char* key = a;
149
				char* value = "";
150
 
151
				int j;
4 nishi 152
				for(j = 0; key[j] != 0; j++) {
153
					if(key[j] == '=') {
2 nishi 154
						key[j] = 0;
155
						value = key + j + 1;
156
						break;
157
					}
158
				}
159
 
160
				struct q_entry* e = malloc(sizeof(*e));
161
				e->key = kn_strdup(key);
162
				e->value = kn_strdup(value);
163
 
164
				struct q_entry** old = entries;
4 nishi 165
				for(j = 0; old[j] != NULL; j++)
166
					;
2 nishi 167
				entries = malloc(sizeof(*entries) * (j + 2));
168
				for(j = 0; old[j] != NULL; j++) entries[j] = old[j];
169
				entries[j] = e;
170
				entries[j + 1] = NULL;
171
				free(old);
172
 
173
				free(a);
174
 
175
				incr = i + 1;
176
				if(query[i] == 0) break;
177
			}
178
		}
179
	}
4 nishi 180
	if(kn_get_query("page") == NULL) {
2 nishi 181
		printf("Status: 200 OK\n\n");
182
		showmain = true;
4 nishi 183
	} else {
6 nishi 184
		bool cond = false;
185
#ifdef MANPAGE_DIRS
186
		int i;
187
		const char* dirs[] = MANPAGE_DIRS;
7 nishi 188
		for(i = 0; i < sizeof(dirs) / sizeof(*dirs); i++) {
6 nishi 189
			cond = (path = kn_find(dirs[i], kn_get_query("page"))) != NULL;
190
			if(cond) break;
191
		}
192
#else
193
		cond = (path = kn_find(MANPAGE_DIR, kn_get_query("page"))) != NULL;
194
#endif
195
		if(cond) {
4 nishi 196
			printf("Status: 200 OK\n\n");
197
		} else {
198
			printf("Status: 404 Not Found\n\n");
199
			no = true;
200
		}
2 nishi 201
	}
202
}
203
 
4 nishi 204
void kn_cgi(void) {
2 nishi 205
	printf("<html>\n");
206
	printf("	<head>\n");
207
	printf("		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
208
	printf("		<title>Keine - ");
4 nishi 209
	if(no) {
2 nishi 210
		printf("Not found");
4 nishi 211
	} else if(showmain) {
2 nishi 212
		printf("Main");
4 nishi 213
	} else {
214
		printf("%s", kn_get_query("page"));
2 nishi 215
	}
216
	printf("</title>\n");
217
	printf("		<style>\n");
218
	printf("html {\n");
219
	printf("	background-color: #222222;\n");
220
	printf("	color: #ffffff;\n");
221
	printf("}\n");
222
	printf("body {\n");
223
	printf("	width: 900px;\n");
224
	printf("	margin: 0 auto;\n");
225
	printf("}\n");
226
	printf("a:link {\n");
227
	printf("	color: #88f;\n");
228
	printf("}\n");
229
	printf("a:visited {\n");
230
	printf("	color: #44b;\n");
231
	printf("}\n");
232
	printf("		</style>\n");
233
	printf("	</head>\n");
234
	printf("	<body>\n");
235
	printf("		<div style=\"text-align: center;\">\n");
236
	printf("			<form action=\"%s%s\">\n", getenv("SCRIPT_NAME"), kn_null(getenv("PATH_INFO")));
237
	printf("				<a href=\"%s%s\">Main</a> | ", getenv("SCRIPT_NAME"), kn_null(getenv("PATH_INFO")));
6 nishi 238
	printf("				Name: <input name=\"page\"%s%s%s>\n", kn_get_query("page") == NULL ? "" : " value=\"", kn_get_query("page") == NULL ? "" : kn_get_query("page"), kn_get_query("page") == NULL ? "" : "\"");
2 nishi 239
	printf("				<input type=\"submit\">\n");
240
	printf("			</form>\n");
241
	printf("		</div>\n");
242
	printf("		<hr>\n");
4 nishi 243
	if(no) {
2 nishi 244
		printf("		Not found.\n");
4 nishi 245
	} else if(showmain) {
6 nishi 246
#ifdef MAIN_HTML
4 nishi 247
		printf("%s", MAIN_HTML);
6 nishi 248
#else
249
		printf("<h1>Index</h1>\n");
250
		printf("<table border=\"0\" style=\"width: 900px;\">\n");
251
		printf("	<tr>\n");
252
		printf("		<th style=\"width: 50px;\">Name</th>\n");
253
		printf("		<th>Description</th>\n");
254
		printf("	</tr>\n");
255
		list_manpages();
256
		printf("</table>\n");
257
#endif
4 nishi 258
	} else {
259
		printf("<pre>");
260
		char* c = kn_manpage_process(path);
261
		if(c != NULL) {
262
			printf("%s", c);
263
			free(c);
264
		}
265
		printf("</pre>\n");
2 nishi 266
	}
267
	printf("		<hr>\n");
5 nishi 268
#ifdef FOOTER_HTML
269
	printf("%s\n", FOOTER_HTML);
270
	printf("		<hr>\n");
271
#endif
4 nishi 272
	printf("		<i>Generated by <a href=\"http://nishi.boats/keine\">Keine</a> %s</i>\n", kn_get_version());
2 nishi 273
	printf("	</body>\n");
274
	printf("</html>\n");
4 nishi 275
	if(path != NULL) free(path);
2 nishi 276
}