💾 Archived View for gemini.rmf-dev.com › repo › Vaati › VgmiTL › files › e7d55ef4bc755e87567d95ae0fe… captured on 2022-07-16 at 17:13:17. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

0 /* See LICENSE file for copyright and license details. */

1 #include <string.h>

2 #include <strings.h>

3 #include <termbox.h>

4 #include "input.h"

5 #include "gemini.h"

6 #include "display.h"

7 #include "cert.h"

8 #include <stdio.h>

9 #ifdef __linux__

10 #include <bsd/string.h>

11 #endif

12

13 int command() {

14 struct gmi_tab* tab = &client.tabs[client.tab];

15 struct gmi_page* page = &tab->page;

16

17 // Trim

18 for (int i=strnlen(client.input.field, sizeof(client.input.field)) - 1;

19 client.input.field[i] == ' ' || client.input.field[i] == '\t'; i--)

20 client.input.field[i] = '\0';

21

22 if (client.input.field[1] == 'q' && client.input.field[2] == '\0') {

23 client.tabs_count--;

24 gmi_freetab(&client.tabs[client.tab]);

25 for (int i = client.tab; i < client.tabs_count; i++) {

26 client.tabs[i] = client.tabs[i+1];

27 }

28 if (client.tab > 0 && client.tab == client.tabs_count)

29 client.tab--;

30 client.input.field[0] = '\0';

31 if (client.tabs_count < 1)

32 return 1;

33 return 0;

34 }

35 if (client.input.field[1] == 'q' && client.input.field[2] == 'a'

36 && client.input.field[3] == '\0')

37 return 1;

38 if (client.input.field[1] == 'n' && client.input.field[2] == 't'

39 && client.input.field[3] == '\0') {

40 gmi_newtab();

41 client.tab = client.tabs_count - 1;

42 client.input.field[0] = '\0';

43 return 0;

44 }

45 if (client.input.field[1] == 'n' && client.input.field[2] == 't'

46 && client.input.field[3] == ' ') {

47 client.input.cursor = 0;

48 int id = atoi(&client.input.field[4]);

49 if (id != 0 || (client.input.field[4] == '0' && client.input.field[5] == '\0')) {

50 gmi_goto_new(id);

51 client.input.field[0] = '\0';

52 } else {

53 gmi_newtab();

54 client.tab = client.tabs_count - 1;

55 client.input.field[0] = '\0';

56 gmi_request(&client.input.field[4]);

57 }

58 return 0;

59 }

60 if (client.input.field[1] == 'o' && client.input.field[2] == ' ') {

61 char urlbuf[MAX_URL];

62 if (strlcpy(urlbuf, &client.input.field[3], sizeof(urlbuf)) >= sizeof(urlbuf)) {

63 client.input.error = 1;

64 snprintf(tab->error, sizeof(tab->error), "Url too long");

65 return 0;

66 }

67 client.input.field[0] = '\0';

68 gmi_cleanforward(tab);

69 int bytes = gmi_request(urlbuf);

70 if (bytes > 0) {

71 tab->scroll = -1;

72 }

73 if (page->code == 11 || page->code == 10) {

74 client.input.mode = 1;

75 client.input.cursor = 0;

76 client.input.error = 0;

77 }

78 tab->selected = 0;

79 return 0;

80 }

81 if (client.input.field[1] == 's' && client.input.field[2] == ' ') {

82 char urlbuf[MAX_URL];

83 snprintf(urlbuf, sizeof(urlbuf),

84 "gemini://geminispace.info/search?%!s(MISSING)", &client.input.field[3]);

85 client.input.field[0] = '\0';

86 gmi_cleanforward(tab);

87 int bytes = gmi_request(urlbuf);

88 if (bytes > 0) {

89 tab->scroll = -1;

90 }

91 if (page->code == 11 || page->code == 10) {

92 client.input.mode = 1;

93 client.input.cursor = 0;

94 client.input.error = 0;

95 }

96 tab->selected = 0;

97 return 0;

98 }

99 if (client.input.field[1] == 'a' && client.input.field[2] == 'd'

100 && client.input.field[3] == 'd' &&

101 (client.input.field[4] == ' ' || client.input.field[4] == '\0')) {

102 char* title = client.input.field[4] == '\0'?NULL:&client.input.field[5];

103 gmi_addbookmark(tab->url, title);

104 client.input.field[0] = '\0';

105 tab->selected = 0;

106 if (!strcmp("about:home", tab->url)) {

107 gmi_freetab(tab);

108 gmi_gohome(tab);

109 }

110 return 0;

111 }

112 if (strcmp(client.input.field, ":gencert") == 0) {

113 char host[256];

114 gmi_parseurl(client.tabs[client.tab].url, host, sizeof(host), NULL, 0, NULL);

115 cert_create(host);

116 client.input.field[0] = '\0';

117 tab->selected = 0;

118 return 0;

119 }

120 if (atoi(&client.input.field[1]) ||

121 (client.input.field[1] == '0' && client.input.field[2] == '\0')) {

122 int bytes = gmi_goto(atoi(&client.input.field[1]));

123 if (bytes > 0) {

124 tab->scroll = -1;

125 }

126 client.input.field[0] = '\0';

127 tab->selected = 0;

128 return 0;

129 }

130 if (client.input.field[1] == '\0') client.input.field[0] = '\0';

131 else {

132 client.input.error = -1;

133 snprintf(tab->error, sizeof(tab->error),

134 "Unknown input: %!s(MISSING)", &client.input.field[1]);

135 }

136 return 0;

137 }

138

139 int input(struct tb_event ev) {

140 struct gmi_tab* tab = &client.tabs[client.tab];

141 struct gmi_page* page = &tab->page;

142 if (page->code == 11 || page->code == 10) {

143 if (!client.input.mode) client.input.cursor = 0;

144 client.input.mode = 1;

145 client.input.error = 0;

146 }

147 if (ev.type == TB_EVENT_RESIZE) {

148 int lines = gmi_render(tab);

149 tab->scroll -= page->lines - lines;

150 if (tab->scroll+tb_height()-2 > lines) tab->scroll = lines - tb_height() + 2;

151 tb_clear();

152 return 0;

153 }

154 if (ev.type != TB_EVENT_KEY) return 0;

155

156 if (!client.input.mode && ev.key == TB_KEY_ESC) {

157 bzero(client.vim.counter, sizeof(client.vim.counter));

158 client.vim.g = 0;

159 }

160 if (client.input.mode && ev.key == TB_KEY_ESC) {

161 client.input.mode = 0;

162 client.input.cursor = 0;

163 if (page->code == 11 || page->code == 10) {

164 page->code = 0;

165 gmi_request(tab->history->url);

166 }

167 client.input.field[0] = '\0';

168 tb_hide_cursor();

169 return 0;

170 }

171 if (client.input.mode && (ev.key == TB_KEY_BACKSPACE2 || ev.key == TB_KEY_BACKSPACE)) {

172 int i = client.input.cursor;

173 if (i>((page->code==10||page->code==11)?0:1)) {

174 strlcpy(&client.input.field[i-1],

175 &client.input.field[i], sizeof(client.input.field)-i);

176 client.input.cursor--;

177 }

178 return 0;

179 }

180 if (ev.key == TB_KEY_DELETE) {

181 if (strcmp(tab->url, "about:home")) return 0;

182 if (tab->selected && tab->selected > 0 && tab->selected <= page->links_count) {

183 gmi_removebookmark(tab->selected);

184 tab->selected = 0;

185 gmi_freetab(tab);

186 gmi_gohome(tab);

187 }

188 return 0;

189 }

190 if (ev.key == TB_KEY_BACK_TAB) {

191 if (tab->selected && tab->selected > 0 && tab->selected <= page->links_count) {

192 int linkid = tab->selected;

193 tab->selected = 0;

194 gmi_goto_new(linkid);

195 }

196 return 0;

197 }

198 if (!client.input.mode && ev.key == TB_KEY_TAB) {

199 if (client.vim.counter[0] != '\0' && atoi(client.vim.counter)) {

200 tab->selected = atoi(client.vim.counter);

201 bzero(client.vim.counter, sizeof(client.vim.counter));

202 if (tab->selected > page->links_count) {

203 snprintf(tab->error, sizeof(tab->error),

204 "Invalid link number");

205 tab->selected = 0;

206 client.input.error = 1;

207 }

208 else if (strlcpy(tab->selected_url, page->links[tab->selected - 1],

209 sizeof(tab->selected_url)) >= sizeof(tab->selected_url)) {

210 snprintf(tab->error, sizeof(tab->error),

211 "Invalid link, above %!l(MISSING)u characters",

212 sizeof(tab->selected_url));

213 tab->selected = 0;

214 client.input.error = 1;

215 }

216 }

217 else if (tab->selected) {

218 gmi_goto(tab->selected);

219 tab->selected = 0;

220 }

221 client.vim.g = 0;

222 return 0;

223 }

224 if (!client.input.mode && ev.key == TB_KEY_ENTER) {

225 if (client.vim.counter[0] != '\0' && atoi(client.vim.counter)) {

226 tab->scroll += atoi(client.vim.counter);

227 bzero(client.vim.counter, sizeof(client.vim.counter));

228 if (tab->scroll+tb_height()-2>page->lines)

229 tab->scroll = page->lines - tb_height() + 2;

230 }

231 else if (tab->scroll+tb_height()-2<page->lines) tab->scroll++;

232 client.vim.g = 0;

233 return 0;

234 }

235 if (client.input.mode && ev.key == TB_KEY_ENTER) {

236 client.input.mode = 0;

237 tb_hide_cursor();

238 if (page->code == 10 || page->code == 11) {

239 char urlbuf[MAX_URL];

240 char* start = strstr(tab->url, "gemini://");

241 char* request = strrchr(tab->url, '?');

242 if (!(start?strchr(&start[GMI], '/'):strchr(tab->url, '/')))

243 snprintf(urlbuf, sizeof(urlbuf),

244 "%!s(MISSING)/?%!s(MISSING)", tab->url, client.input.field);

245 else if (request && request > strrchr(tab->url, '/')) {

246 *request = '\0';

247 snprintf(urlbuf, sizeof(urlbuf),

248 "%!s(MISSING)?%!s(MISSING)", tab->url, client.input.field);

249 *request = '?';

250 } else

251 snprintf(urlbuf, sizeof(urlbuf),

252 "%!s(MISSING)?%!s(MISSING)", tab->url, client.input.field);

253 int bytes = gmi_request(urlbuf);

254 if (bytes>0) {

255 tab = &client.tabs[client.tab];

256 tab->scroll = -1;

257 }

258 client.input.field[0] = '\0';

259 return 0;

260 }

261 return command();

262 }

263 if (client.input.mode && ev.key == TB_KEY_ARROW_LEFT && ev.mod == TB_MOD_CTRL) {

264 while (client.input.cursor>1) {

265 client.input.cursor--;

266 if (client.input.field[client.input.cursor] == ' ' ||

267 client.input.field[client.input.cursor] == '.')

268 break;

269 }

270 return 0;

271 }

272 if (client.input.mode && ev.key == TB_KEY_ARROW_LEFT) {

273 if (client.input.cursor>1)

274 client.input.cursor--;

275 return 0;

276 }

277 if (client.input.mode && ev.key == TB_KEY_ARROW_RIGHT && ev.mod == TB_MOD_CTRL) {

278 while (client.input.field[client.input.cursor]) {

279 client.input.cursor++;

280 if (client.input.field[client.input.cursor] == ' ' ||

281 client.input.field[client.input.cursor] == '.')

282 break;

283 }

284 return 0;

285 }

286 if (client.input.mode && ev.key == TB_KEY_ARROW_RIGHT) {

287 if (client.input.field[client.input.cursor])

288 client.input.cursor++;

289 return 0;

290 }

291 unsigned int l = strnlen(client.input.field, sizeof(client.input.field));

292 if (client.input.mode && ev.ch && l < sizeof(client.input.field)) {

293 for (int i = l-1; i >= client.input.cursor; i--) {

294 client.input.field[i+1] = client.input.field[i];

295 }

296 client.input.field[client.input.cursor] = ev.ch;

297 client.input.cursor++;

298 l++;

299 client.input.field[l] = '\0';

300 return 0;

301 } else

302 tb_hide_cursor();

303

304 if (ev.key == TB_KEY_PGUP) {

305 int counter = atoi(client.vim.counter);

306 if (!counter) counter++;

307 int H = tb_height() - 2 - (client.tabs_count>1);

308 tab->scroll -= counter * H;

309 bzero(client.vim.counter, sizeof(client.vim.counter));

310 if (tab->scroll < -1) tab->scroll = -1;

311 client.vim.g = 0;

312 return 0;

313 }

314 if (ev.key == TB_KEY_PGDN) {

315 int counter = atoi(client.vim.counter);

316 if (!counter) counter++;

317 int H = tb_height() - 2 - (client.tabs_count>1);

318 tab->scroll += counter * H;

319 bzero(client.vim.counter, sizeof(client.vim.counter));

320 if (page->lines <= H) tab->scroll = -1;

321 else if (tab->scroll + H >page->lines)

322 tab->scroll = page->lines - H;

323 client.vim.g = 0;

324 return 0;

325 }

326 switch (ev.ch) {

327 case 'u':

328 client.input.mode = 1;

329 snprintf(client.input.field, sizeof(client.input.field), ":o %!s(MISSING)", tab->url);

330 client.input.cursor = strnlen(client.input.field, sizeof(client.input.field));

331 break;

332 case ':':

333 client.input.error = 0;

334 client.input.mode = 1;

335 client.input.cursor = 1;

336 client.input.field[0] = ':';

337 client.input.field[1] = '\0';

338 break;

339 case 'r': // Reload

340 if (!strcmp("about:home", tab->url)) {

341 gmi_freetab(tab);

342 gmi_gohome(tab);

343 break;

344 }

345 if (!tab->history) break;

346 gmi_request(tab->history->url);

347 struct gmi_link* prev = tab->history->prev;

348 prev->next = NULL;

349 free(tab->history);

350 tab->history = prev;

351 break;

352 case 'h': // Tab left

353 client.tab--;

354 if (client.tab < 0) client.tab = client.tabs_count - 1;

355 break;

356 case 'l': // Tab right

357 client.tab++;

358 if (client.tab >= client.tabs_count) client.tab = 0;

359 break;

360 case 'H': // Back

361 if (!tab->history) break;

362 if (page->code == 20 || page->code == 10 || page->code == 11) {

363 if (!tab->history->prev) break;

364 tab->history->scroll = tab->scroll;

365 tab->history = tab->history->prev;

366 tab->scroll = tab->history->scroll;

367 }

368 if (gmi_request(tab->history->url) < 0) break;

369 break;

370 case 'L': // Forward

371 if (!tab->history || !tab->history->next) break;

372 if (gmi_request(tab->history->next->url) < 0) break;

373 tab->history->scroll = tab->scroll;

374 tab->history = tab->history->next;

375 tab->scroll = tab->history->scroll;

376 break;

377 case 'k': // UP

378 if (client.vim.counter[0] != '\0' && atoi(client.vim.counter)) {

379 tab->scroll -= atoi(client.vim.counter);

380 bzero(client.vim.counter, sizeof(client.vim.counter));

381 if (tab->scroll < -1) tab->scroll = -1;

382 }

383 else if (tab->scroll>-1) tab->scroll--;

384 client.vim.g = 0;

385 break;

386 case 'j': // DOWN

387 if (client.vim.counter[0] != '\0' && atoi(client.vim.counter)) {

388 tab->scroll += atoi(client.vim.counter);

389 bzero(client.vim.counter, sizeof(client.vim.counter));

390 if (tab->scroll+tb_height()-2>page->lines)

391 tab->scroll = page->lines - tb_height() + 2;

392 }

393 else if (tab->scroll+(client.tabs_count==1?tb_height()-2:tb_height()-3)

394 < page->lines) tab->scroll++;

395 client.vim.g = 0;

396 break;

397 case 'f': // Show history

398 display_history();

399 break;

400 case 'g': // Start of file

401 if (client.vim.g) {

402 tab->scroll = -1;

403 client.vim.g = 0;

404 } else client.vim.g++;

405 break;

406 case 'G': // End of file

407 tab->scroll = page->lines-tb_height()+2;

408 if (client.tabs_count != 1) tab->scroll++;

409 if (tb_height()-2-(client.tabs_count>1) > page->lines) tab->scroll = -1;

410 break;

411 default:

412 if (!(ev.ch >= '0' && ev.ch <= '9'))

413 break;

414 unsigned int len = strnlen(client.vim.counter, sizeof(client.vim.counter));

415 if (len == 0 && ev.ch == '0') break;

416 if (len >= sizeof(client.vim.counter)) break;

417 client.vim.counter[len] = ev.ch;

418 client.vim.counter[len+1] = '\0';

419 }

420 return 0;

421 }

422