AmendHub

Download

jcs

/

subtext

/

main.c

 

(View History)

jcs   main: Hook up ipdb Latest amendment: 512 on 2023-06-15

1 /*
2 * Copyright (c) 2020-2023 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "subtext.h"
21 #include "binkp.h"
22 #include "console.h"
23 #include "db.h"
24 #include "focusable.h"
25 #include "logger.h"
26 #include "mail.h"
27 #include "main_menu.h"
28 #include "serial_local.h"
29 #include "session.h"
30 #include "settings.h"
31 #include "telnet.h"
32 #include "user.h"
33 #include "uthread.h"
34 #include "util.h"
35
36 MenuHandle apple_menu, file_menu;
37 short quitting = 0;
38 struct db *db = NULL;
39 bool blanker_on = false;
40 unsigned long blanker_last_blank = 0;
41 WindowPtr blanker_win = NULL;
42 struct uthread *periodic_job_thread = NULL;
43
44 bool handle_menu(long menu_id);
45 void handle_exit(void);
46 void blanker_idle(void);
47 void periodic_jobs(struct uthread *uthread, void *arg);
48
49 int
50 main(void)
51 {
52 Handle mbar;
53 EventRecord event;
54 WindowPtr event_win;
55 GrafPtr old_port;
56 AppFile finder_file;
57 struct focusable *found_focusable;
58 unsigned long zone_size, stack_size, heap_size;
59 short event_in, n, finder_action, finder_count;
60 char key;
61
62 uthread_init();
63
64 InitGraf(&thePort);
65 InitFonts();
66 FlushEvents(everyEvent, 0);
67 InitWindows();
68 InitMenus();
69 TEInit();
70 InitDialogs(0);
71 InitCursor();
72 MaxApplZone();
73
74 util_init();
75
76 if (!(mbar = GetNewMBar(MBAR_ID)))
77 panic("no mbar");
78 SetMenuBar(mbar);
79 if (!(apple_menu = GetMHandle(APPLE_MENU_ID)))
80 panic("no apple menu");
81 AddResMenu(apple_menu, 'DRVR');
82 if (!(file_menu = GetMHandle(FILE_MENU_ID)))
83 panic("no file menu");
84 InsertMenu(GetMenu(VIEWS_SUBMENU_ID), -1);
85 DrawMenuBar();
86
87 /* see if we were started by double-clicking a .bbs file */
88 CountAppFiles(&finder_action, &finder_count);
89 if (finder_count) {
90 GetAppFiles(1, &finder_file);
91 ClrAppFiles(1);
92 finder_count = 0;
93 db = db_open(finder_file.fName, finder_file.vRefNum);
94 } else {
95 char none = 0;
96 db = db_open(*((Str255 *)&none), 0);
97 }
98
99 if (!db)
100 panic("Failed to open database");
101
102 _atexit(handle_exit);
103
104 logger_init();
105 logger_update_title();
106
107 zone_size = (unsigned long)CurStackBase - (unsigned long)ApplZone;
108 stack_size = (unsigned long)CurStackBase - (unsigned long)ApplLimit;
109 heap_size = (unsigned long)ApplLimit - (unsigned long)ApplZone;
110 logger_printf("Initialized with %ldKB zone, %ldKB stack for "
111 "%d threads, %ldKB heap", zone_size / 1024L, stack_size / 1024L,
112 NUM_UTHREADS, heap_size / 1024L);
113
114 db_cache_boards(db);
115 db_cache_folders(db);
116
117 main_menu_init();
118
119 logger_printf("[db] Updating username cache");
120 user_cache_usernames();
121
122 binkp_init();
123 if (db->config.telnet_port)
124 telnet_init();
125 if (db->config.modem_port)
126 serial_init();
127 if (db->config.ipdb_path[0])
128 db->ipdb = ipdb_open(db->config.ipdb_path);
129
130 blanker_last_blank = Time;
131
132 periodic_job_thread = uthread_add(periodic_jobs, NULL);
133
134 while (!quitting) {
135 if (db->config.telnet_port)
136 telnet_idle();
137 if (db->config.modem_port)
138 serial_idle();
139
140 uthread_coordinate();
141
142 SystemTask();
143 if (!GetNextEvent(everyEvent, &event)) {
144 blanker_idle();
145 continue;
146 }
147
148 switch (event.what) {
149 case nullEvent:
150 for (n = 0; n < nfocusables; n++) {
151 if (focusables[n]->idle)
152 focusables[n]->idle(focusables[n], &event);
153 }
154 break;
155 case keyDown:
156 case autoKey:
157 if (blanker_on) {
158 blanker_unblank();
159 break;
160 }
161 key = event.message & charCodeMask;
162 if ((event.modifiers & cmdKey) != 0 &&
163 handle_menu(MenuKey(key)) == true)
164 break;
165 else if (nfocusables && focusables[0]->visible &&
166 focusables[0]->key_down)
167 focusables[0]->key_down(focusables[0], &event);
168 break;
169 case mouseDown:
170 event_in = FindWindow(event.where, &event_win);
171
172 switch (event_in) {
173 case inMenuBar:
174 handle_menu(MenuSelect(event.where));
175 break;
176 case inSysWindow:
177 SystemClick(&event, event_win);
178 break;
179 case inDrag:
180 SelectWindow(event_win);
181 DragWindow(event_win, event.where, &screenBits.bounds);
182 break;
183 case inGrow:
184 found_focusable = find_focusable(event_win);
185 if (event_win != FrontWindow()) {
186 if (found_focusable)
187 show_focusable(found_focusable);
188 }
189 if (found_focusable && found_focusable->resize)
190 found_focusable->resize(found_focusable, &event);
191 break;
192 case inGoAway:
193 if (TrackGoAway(event_win, event.where)) {
194 found_focusable = find_focusable(event_win);
195 if (found_focusable && found_focusable->close)
196 found_focusable->close(found_focusable, &event);
197 }
198 break;
199 case inContent:
200 if (blanker_on) {
201 blanker_unblank();
202 break;
203 }
204 found_focusable = find_focusable(event_win);
205 if (event_win != FrontWindow()) {
206 if (found_focusable)
207 show_focusable(found_focusable);
208 }
209 if (found_focusable && found_focusable->mouse_down)
210 found_focusable->mouse_down(found_focusable, &event);
211 break;
212 }
213 break;
214 case updateEvt:
215 event_win = (WindowPtr)event.message;
216
217 GetPort(&old_port);
218 SetPort(event_win);
219 BeginUpdate(event_win);
220
221 found_focusable = find_focusable(event_win);
222 if (found_focusable && found_focusable->update)
223 found_focusable->update(found_focusable, &event);
224
225 EndUpdate(event_win);
226 SetPort(old_port);
227 break;
228 case activateEvt:
229 break;
230 case app4Evt:
231 if (HiWord(event.message) & (1 << 8)) {
232 /* multifinder suspend/resume */
233 switch (event.message & (1 << 0)) {
234 case 0:
235 /* suspend */
236 for (n = 0; n < nfocusables; n++) {
237 if (focusables[n]->suspend)
238 focusables[n]->suspend(focusables[n], &event);
239 }
240 break;
241 case 1:
242 /* resume */
243 for (n = 0; n < nfocusables; n++) {
244 if (focusables[n]->resume)
245 focusables[n]->resume(focusables[n], &event);
246 }
247 break;
248 }
249 }
250 break;
251 }
252 }
253
254 return 0;
255 }
256
257 void
258 handle_exit(void)
259 {
260 short n;
261
262 blanker_unblank();
263
264 for (n = 0; n < nfocusables; n++) {
265 if (focusables[n]->atexit)
266 focusables[n]->atexit(focusables[n]);
267 }
268
269 binkp_atexit();
270
271 if (db->config.telnet_port)
272 telnet_atexit();
273 if (db->config.modem_port)
274 serial_atexit();
275 if (db->ipdb)
276 ipdb_close(&db->ipdb);
277
278 db_close(db);
279 }
280
281 bool
282 handle_menu(long menu_id)
283 {
284 bool ret = false, quit;
285 size_t n;
286
287 switch (HiWord(menu_id)) {
288 case APPLE_MENU_ID:
289 switch (LoWord(menu_id)) {
290 case APPLE_MENU_ABOUT_ID:
291 about(PROGRAM_NAME);
292 break;
293 default: {
294 Str255 da;
295 GrafPtr save_port;
296
297 GetItem(apple_menu, LoWord(menu_id), &da);
298 GetPort(&save_port);
299 OpenDeskAcc(da);
300 SetPort(save_port);
301 break;
302 }
303 }
304 break;
305 case FILE_MENU_ID:
306 switch (LoWord(menu_id)) {
307 case FILE_MENU_QUIT_ID: {
308 int tnfocusables = nfocusables;
309 struct focusable **tfocusables;
310
311 ret = true;
312 quit = true;
313
314 if (nfocusables) {
315 /*
316 * nfocusables and focusables array will probably be
317 * modified as each focusable quits
318 */
319 tfocusables = xcalloc(sizeof(Ptr), tnfocusables);
320 if (tfocusables == NULL)
321 ExitToShell();
322
323 memcpy(tfocusables, focusables,
324 sizeof(Ptr) * tnfocusables);
325
326 for (n = 0; n < tnfocusables; n++) {
327 if (tfocusables[n] && tfocusables[n]->quit &&
328 !tfocusables[n]->quit(tfocusables[n])) {
329 quit = false;
330 break;
331 }
332 }
333
334 xfree(&tfocusables);
335 }
336 if (quit)
337 ExitToShell();
338 break;
339 }
340 }
341 break;
342 case EDIT_MENU_ID:
343 if (nfocusables && focusables[0]->visible && focusables[0]->menu)
344 ret = focusables[0]->menu(focusables[0], HiWord(menu_id),
345 LoWord(menu_id));
346 break;
347 case BBS_MENU_ID:
348 switch (LoWord(menu_id)) {
349 case BBS_MENU_OPEN_CONSOLE_ID:
350 console_init();
351 break;
352 case BBS_MENU_EDIT_MENUS_ID:
353 main_menu_edit();
354 break;
355 }
356 ret = true;
357 break;
358 case VIEWS_SUBMENU_ID:
359 switch (LoWord(menu_id)) {
360 case VIEWS_SUBMENU_ISSUE_ID:
361 view_editor_show(DB_TEXT_ISSUE_ID, "Edit: Pre-login view");
362 break;
363 case VIEWS_SUBMENU_MAIN_MENU_ID:
364 view_editor_show(DB_TEXT_MENU_ID, "Edit: Main menu");
365 break;
366 case VIEWS_SUBMENU_SHORT_MENU_ID:
367 view_editor_show(DB_TEXT_SHORTMENU_ID, "Edit: Short menu");
368 break;
369 case VIEWS_SUBMENU_SIGNUP_ID:
370 view_editor_show(DB_TEXT_SIGNUP_ID, "Edit: Signup view");
371 break;
372 case VIEWS_SUBMENU_PAGE_SYSOP_ID:
373 view_editor_show(DB_TEXT_PAGE_SYSOP_ID, "Edit: Page Sysop view");
374 break;
375 case VIEWS_SUBMENU_NO_FREE_NODES_ID:
376 view_editor_show(DB_TEXT_NO_FREE_NODES_ID, "Edit: No Free Nodes view");
377 break;
378 case VIEWS_SUBMENU_SIGNOFF_ID:
379 view_editor_show(DB_TEXT_SIGNOFF_ID, "Edit: Session Signoff view");
380 break;
381 }
382 ret = true;
383 break;
384 }
385
386 HiliteMenu(0);
387 return ret;
388 }
389
390 void
391 blanker_idle(void)
392 {
393 if (db->config.blanker_idle_seconds == 0)
394 return;
395
396 if (!blanker_on && !nsessions &&
397 (Time - blanker_last_blank > db->config.blanker_idle_seconds)) {
398 HideMenuBar();
399
400 blanker_win = NewWindow(0L, &screenBits.bounds, "\p", false,
401 plainDBox, (WindowPtr)-1L, true, 0);
402 if (!blanker_win)
403 panic("NewWindow failed");
404 ShowWindow(blanker_win);
405 SetPort(blanker_win);
406 HideCursor();
407 FillRect(&screenBits.bounds, black);
408 blanker_last_blank = Time;
409 blanker_on = true;
410 return;
411 }
412
413 if (blanker_on && (nsessions ||
414 (Time - blanker_last_blank >= db->config.blanker_runtime_seconds)))
415 blanker_unblank();
416 }
417
418 void
419 blanker_unblank(void)
420 {
421 unsigned long rt;
422
423 if (!blanker_on || !blanker_win)
424 return;
425
426 rt = Time - blanker_last_blank;
427
428 ShowCursor();
429 DisposeWindow(blanker_win);
430 blanker_win = NULL;
431 RestoreHiddenMenuBar();
432 blanker_last_blank = Time;
433 blanker_on = false;
434
435 /*
436 * This will call back to blanker_unblank, so it must be done after
437 * blanker_on = false
438 */
439 logger_printf("[blanker] Blanked screen for %ld second%s",
440 rt, rt == 1 ? "" : "s");
441 }
442
443 void
444 periodic_jobs(struct uthread *uthread, void *arg)
445 {
446 struct tm *date_tm;
447 size_t n;
448 short last_daily_job = -1;
449
450 for (;;) {
451 date_tm = localtime((time_t *)&Time);
452
453 if (last_daily_job != date_tm->tm_mday) {
454 if (nsessions != 0)
455 goto sleep;
456
457 if (db->config.session_log_prune_days) {
458 session_prune_logs(db->config.session_log_prune_days);
459 uthread_yield();
460 }
461
462 if (db->config.mail_prune_days) {
463 mail_prune(db->config.mail_prune_days);
464 uthread_yield();
465 }
466
467 for (n = 0; n < db->nboards; n++) {
468 board_prune_old_posts(&db->boards[n]);
469 uthread_yield();
470 }
471
472 last_daily_job = date_tm->tm_mday;
473 }
474
475 if (binkp_ready && (nsessions == 0 || binkp_next_poll == 0)) {
476 /*
477 * Only do polling when no one is on, or we were just woken up
478 * from the sysop menu
479 */
480 if (Time > binkp_next_poll) {
481 binkp_poll();
482 uthread_yield();
483 }
484
485 if (binkp_packets_in_outbox())
486 binkp_poll();
487 }
488
489 sleep:
490 uthread_msleep((unsigned long)1000 * 10);
491 }
492
493 periodic_job_thread = NULL;
494 }