0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "strlcpy.h"
8 #include "macro.h"
9 #include "strnstr.h"
10 #include "config.h"
11 #include "page.h"
12 #include "client.h"
13 #include "tab.h"
14 #include "request.h"
15 #include "certificate.h"
16 #include "error.h"
17 #include "parser.h"
18
19 static int need_argument(struct client * client,
20 const char *field, size_t len, char *error) {
21 if (!(!len || !*field)) return 0;
22 client->error = 1;
23 STRLCPY(client->cmd, error);
24 return 1;
25 }
26
27 static int no_argument(struct client * client, const char *field, size_t len) {
28 if (!len || !*field) return 0;
29 client->error = 1;
30 snprintf(V(client->cmd), "Trailing characters: %s", field);
31 return 1;
32 }
33
34 int command_quit(struct client *client, const char* ptr, size_t len) {
35 if (no_argument(client, ptr, len)) return 0;
36 return 1;
37 }
38
39 int command_close(struct client *client, const char* ptr, size_t len) {
40 if (no_argument(client, ptr, len)) return 0;
41 client_closetab(client);
42 return !client->tab;
43 }
44
45 int command_newtab(struct client *client, const char* ptr, size_t len) {
46
47 int ret;
48 const char *url = "about:newtab";
49
50 if (!client->tab || !len) return 0;
51 if (*ptr) url = ptr;
52
53 if ((ret = client_newtab(client, url))) {
54 client->error = 1;
55 error_string(ret, V(client->cmd));
56 }
57 return 0;
58 }
59
60 int command_search(struct client *client, const char* ptr, size_t len) {
61
62 int ret;
63 char url[MAX_URL];
64
65 if (!client->tab || !len) return 0;
66 if (need_argument(client, ptr, len, "Empty query")) return 0;
67
68 snprintf(V(url), config.searchEngineURL, ptr);
69
70 if ((ret = tab_request(client->tab, url))) {
71 client->error = 1;
72 error_string(ret, V(client->cmd));
73 }
74 return 0;
75 }
76
77 int command_open(struct client *client, const char* ptr, size_t len) {
78
79 size_t link;
80 struct request *req;
81 char buf[MAX_URL];
82 int i;
83
84 if (need_argument(client, ptr, len, "No URL")) return 0;
85 if (!client->tab) return 0;
86
87 STRLCPY(buf, ptr);
88 i = strnlen(V(buf)) - 1;
89 for (; i > 0; i--) {
90 if (buf[i] <= ' ') buf[i] = '\0';
91 }
92
93 link = atoi(buf);
94 if (!link) {
95 tab_request(client->tab, buf);
96 return 0;
97 }
98
99 req = tab_completed(client->tab);
100 if (!req) return 0;
101 link--;
102 if (link >= req->page.links_count) {
103 client->error = 1;
104 STRLCPY(client->cmd, "Invalid link number");
105 return 0;
106 }
107 request_follow(req, req->page.links[link], V(buf));
108 tab_request(client->tab, buf);
109 return 0;
110 }
111
112 int command_gencert(struct client *client, const char* args, size_t len) {
113
114 struct request *req;
115
116 if (no_argument(client, args, len)) return 0;
117
118 req = tab_completed(client->tab);
119 if (!req) {
120 client->error = 1;
121 STRLCPY(client->cmd, "Invalid page");
122 return 0;
123 }
124 if (!strncmp(req->url, V("about:") - 1)) {
125 client->error = 1;
126 STRLCPY(client->cmd,
127 "Cannot create certificate for \"about:\" pages");
128 return 0;
129 }
130 if (certificate_create(req->name, V(client->cmd)))
131 client->error = 1;
132 return 0;
133 }
134
135 #include <time.h>
136 #include "known_hosts.h"
137 int command_forget(struct client *client, const char* ptr, size_t len) {
138
139 const char *host;
140 char buf[MAX_URL];
141 int i, ret;
142
143 if (need_argument(client, ptr, len, "No host")) return 0;
144 if (!client->tab) return 0;
145
146 host = ptr;
147 STRLCPY(buf, host);
148 i = strnlen(V(buf)) - 1;
149 for (; i > 0; i--) {
150 if (buf[i] <= ' ') buf[i] = '\0';
151 }
152
153 if ((ret = known_hosts_forget(buf))) {
154 client->error = 1;
155 error_string(ret, V(client->cmd));
156 return 0;
157 }
158
159 client->error = ERROR_INFO;
160 snprintf(V(client->cmd),
161 "Certificate for %s removed from well-known hosts", buf);
162
163 return 0;
164 }
165
166 #include "storage.h"
167 int command_download(struct client *client, const char* args, size_t len) {
168
169 struct request *req;
170 FILE *f;
171 char name[MAX_URL], *ptr;
172 char buf[MAX_URL];
173 int i;
174
175 req = tab_completed(client->tab);
176 if (!req) {
177 client->error = 1;
178 STRLCPY(client->cmd, "Invalid page");
179 return 0;
180 }
181
182 if (len && *args) {
183 STRLCPY(name, args);
184 } else if (!strnstr(req->url, "://", sizeof(req->url))) {
185 STRLCPY(name, req->url);
186 } else {
187 char *start;
188 size_t i = STRLCPY(buf, req->url);
189 for (; i > 0; i--) {
190 if (WHITESPACE(buf[i])) buf[i] = 0;
191 else if (buf[i] == '/') buf[i] = 0;
192 else break;
193 }
194 ptr = strrchr(buf, '/');
195 if (!ptr) ptr = buf;
196 else ptr++;
197 start = ptr;
198 for (i = 0; *ptr; i++) ptr++;
199 if (i < 2) STRLCPY(name, req->url);
200 else STRLCPY(name, start);
201 }
202
203 STRLCPY(buf, name);
204 for (i = 1; i < 128 && storage_download_exist(name); i++) {
205 char *dot;
206 dot = strrchr(buf, '.');
207 if (!dot || dot == buf) {
208 snprintf(V(name), "%s (%d)", buf, i);
209 continue;
210 }
211 *dot = '\0';
212 snprintf(V(name), "%s (%d).%s", buf, i, dot + 1);
213 *dot = '.';
214 }
215 f = i < 128 ? storage_download_fopen(name, "wb") : NULL;
216 if (!f) {
217 client->error = 1;
218 error_string(ERROR_ERRNO, V(client->cmd));
219 return 0;
220 }
221 fwrite(&req->data[req->page.offset], 1,
222 req->length - req->page.offset, f);
223 fclose(f);
224
225 client->error = ERROR_INFO;
226 snprintf(V(client->cmd), "File downloaded : %s", name);
227
228 return 0;
229 }
230
231 #include "bookmarks.h"
232 int command_add(struct client *client, const char* args, size_t len) {
233
234 int ret;
235 struct request *req;
236
237 if (!client->tab || !len) return 0;
238 if (!(req = tab_completed(client->tab))) return 0;
239 if (!*args) args = req->page.title;
240 if ((ret = bookmark_add(req->url, args)) ||
241 (ret = bookmark_rewrite())) {
242 error_string(ret, V(client->cmd));
243 client->error = 1;
244 }
245 return 0;
246 }
247
248 int command_help(struct client *client, const char* args, size_t len) {
249 int ret;
250 if (no_argument(client, args, len)) return 0;
251 if (!client->tab) return 0;
252 if ((ret = client_newtab(client, "about:help")) ||
253 (ret = bookmark_rewrite())) {
254 error_string(ret, V(client->cmd));
255 client->error = 1;
256 }
257 return 0;
258 }
259