OSDN Git Service

implement text box edit menu handling.
[bbk/bchanl.git] / src / main.c
1 /*
2  * main.c
3  *
4  * Copyright (c) 2009-2012 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include        <basic.h>
28 #include        <bstdlib.h>
29 #include        <bstdio.h>
30 #include        <bstring.h>
31 #include        <errcode.h>
32 #include        <tstring.h>
33 #include        <keycode.h>
34 #include        <tcode.h>
35 #include        <btron/btron.h>
36 #include        <btron/dp.h>
37 #include        <btron/hmi.h>
38 #include        <btron/vobj.h>
39 #include        <btron/libapp.h>
40 #include        <btron/bsocket.h>
41
42 #include        "window.h"
43 #include        "subjectretriever.h"
44 #include        "subjectcache.h"
45 #include        "subjectparser.h"
46 #include        "subjectlist.h"
47 #include        "subjectlayout.h"
48 #include    "bbsmenuretriever.h"
49 #include    "bbsmenucache.h"
50 #include    "bbsmenuparser.h"
51 #include        "bbsmenufilter.h"
52 #include    "bbsmenulayout.h"
53 #include    "extbbslist.h"
54 #include    "util.h"
55
56 #include    "bchanl_subject.h"
57 #include    "bchanl_hmi.h"
58 #include    "bchanl_menus.h"
59 #include    "bchanl_panels.h"
60
61 #ifdef BCHANL_CONFIG_DEBUG
62 # define DP(arg) printf arg
63 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
64 #else
65 # define DP(arg) /**/
66 # define DP_ER(msg, err) /**/
67 #endif
68
69 #define BCHANL_DBX_MENU_TEST 20
70 #define BCHANL_DBX_TEXT_MLIST0  21
71 #define BCHANL_DBX_TEXT_MLIST1  22
72 #define BCHANL_DBX_TEXT_MLIST2  23
73 #define BCHANL_DBX_VIEWER_FUSEN 24
74 #define BCHANL_DBX_TEXT_WINDOWTITLE_BBSMENU 25
75 #define BCHANL_DBX_TEXT_WINDOWTITLE_SUBJECT 26
76 #define BCHANL_DBX_TEXT_MSG_RETRBBSMENU 27
77 #define BCHANL_DBX_TEXT_MSG_RETRSUBJECT 28
78 #define BCHANL_DBX_TEXT_MSG_ERRRETR 29
79 #define BCHANL_DBX_TB_SBJTOPT_FLT 30
80 #define BCHANL_DBX_WS_SBJTOPT_ODR 31
81 #define BCHANL_DBX_WS_SBJTOPT_ODRBY     32
82 #define BCHANL_DBX_TEXT_CATE_EXTBBS 33
83
84 #define BCHANL_MENU_WINDOW 3
85
86 #define BCHANL_COMMONSTORAGE_EXTBBSLIST_RECTYPE 30
87 #define BCHANL_COMMONSTORAGE_EXTBBSLIST_SUBTYPE 1
88
89 typedef struct bchanl_hmistate_t_ bchanl_hmistate_t;
90 struct bchanl_hmistate_t_ {
91         PTRSTL ptr;
92
93         TC *msg_retr_bbsmenu;
94         TC *msg_retr_subject;
95         TC *msg_error_retr;
96 };
97
98 LOCAL VOID bchanl_hmistate_updateptrstyle(bchanl_hmistate_t *hmistate, PTRSTL ptr)
99 {
100         if (hmistate->ptr == ptr) {
101                 return;
102         }
103         hmistate->ptr = ptr;
104         gset_ptr(hmistate->ptr, NULL, -1, -1);
105 }
106
107 LOCAL VOID bchanl_hmistate_initialize(bchanl_hmistate_t *hmistate)
108 {
109         W err;
110
111         hmistate->ptr = PS_SELECT;
112
113         err = dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_MSG_RETRBBSMENU, (void**)&hmistate->msg_retr_bbsmenu);
114         if (err < 0) {
115                 DP_ER("dget_dtp: message retrieving error", err);
116                 hmistate->msg_retr_bbsmenu = NULL;
117         }
118         err = dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_MSG_RETRSUBJECT, (void**)&hmistate->msg_retr_subject);
119         if (err < 0) {
120                 DP_ER("dget_dtp: message not modified error", err);
121                 hmistate->msg_retr_subject = NULL;
122         }
123         err = dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_MSG_ERRRETR, (void**)&hmistate->msg_error_retr);
124         if (err < 0) {
125                 DP_ER("dget_dtp: message retrieve error error", err);
126                 hmistate->msg_error_retr = NULL;
127         }
128 }
129
130 typedef struct bchanl_bbsmenu_t_ bchanl_bbsmenu_t;
131 struct bchanl_bbsmenu_t_ {
132         W gid;
133
134         bbsmnretriever_t *retriever;
135         bbsmncache_t *cache;
136         bbsmnparser_t *parser;
137         bbsmnfilter_t *filter;
138         bbsmnlayout_t *layout;
139         bbsmndraw_t *draw;
140
141         bchanl_subjecthash_t *subjecthash;
142         extbbslist_t *extbbslist;
143         extbbslist_editcontext_t *editctx;
144         TC *category_extbbs;
145 };
146
147 struct bchanl_t_ {
148         W taskid;
149         W mbfid;
150
151         bchanl_mainmenu_t mainmenu;
152         VID vid;
153         W exectype;
154
155         bchanl_hmistate_t hmistate;
156
157         sbjtretriever_t *retriever;
158
159         bchanl_subjecthash_t *subjecthash;
160         bchanl_bbsmenu_t bbsmenu;
161         bchanl_subject_t *currentsubject;
162
163         bchanlhmi_t *hmi;
164         subjectwindow_t *subjectwindow;
165         bbsmenuwindow_t *bbsmenuwindow;
166         subjectoptionwindow_t *subjectoptionwindow;
167         registerexternalwindow_t *registerexternalwindow;
168         externalbbswindow_t *externalbbswindow;
169 };
170 typedef struct bchanl_t_ bchanl_t;
171
172 LOCAL VOID bchanl_killme(bchanl_t *bchanl);
173
174 LOCAL VOID bchanl_subjectwindow_draw(bchanl_t *bchanl)
175 {
176         sbjtdraw_t *draw;
177         RECT r;
178         if (bchanl->currentsubject == NULL) {
179                 do {
180                         if (subjectwindow_startredisp(bchanl->subjectwindow, &r) == 0) {
181                                 break;
182                         }
183                         subjectwindow_eraseworkarea(bchanl->subjectwindow, &r);
184                 } while (subjectwindow_endredisp(bchanl->subjectwindow) > 0);
185         } else {
186                 draw = bchanl_subject_getdraw(bchanl->currentsubject);
187                 do {
188                         if (subjectwindow_startredisp(bchanl->subjectwindow, &r) == 0) {
189                                 break;
190                         }
191                         subjectwindow_eraseworkarea(bchanl->subjectwindow, &r);
192                         sbjtdraw_draw(draw, &r);
193                 } while (subjectwindow_endredisp(bchanl->subjectwindow) > 0);
194         }
195 }
196
197 LOCAL VOID bchanl_subjectwindow_scroll(bchanl_t *bchanl, W dh, W dv)
198 {
199         sbjtdraw_t *draw;
200         if (bchanl->currentsubject == NULL) {
201                 return;
202         }
203         draw = bchanl_subject_getdraw(bchanl->currentsubject);
204         sbjtdraw_scrollviewrect(draw, dh, dv);
205         subjectwindow_scrollworkarea(bchanl->subjectwindow, -dh, -dv);
206         bchanl_subjectwindow_draw(bchanl);
207 }
208
209 LOCAL VOID bchanl_subjectwindow_resize(bchanl_t *bchanl, SIZE newsize)
210 {
211         W l,t,r,b;
212         sbjtdraw_t *draw;
213
214         if (bchanl->currentsubject == NULL) {
215                 return;
216         }
217         draw = bchanl_subject_getdraw(bchanl->currentsubject);
218
219         sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
220
221         r = l + newsize.h;
222         b = t + newsize.v;
223
224         sbjtdraw_setviewrect(draw, l, t, r, b);
225         subjectwindow_setworkrect(bchanl->subjectwindow, l, t, r, b);
226
227         bchanl_subjectwindow_draw(bchanl);
228 }
229
230 LOCAL VOID bchanl_subjectwindow_close(bchanl_t *bchanl)
231 {
232         bchanl_killme(bchanl);
233 }
234
235 LOCAL VOID bchanl_subjectwindow_press(bchanl_t *bchanl, PNT evpos)
236 {
237         sbjtlist_tuple_t *tuple;
238         sbjtdraw_t *draw;
239         WID wid_butup;
240         W event_type, size, err, fsn_len, dx, dy;
241         void *fsn;
242         GID gid;
243         PNT pos, p1, pos_butup;
244         TR_VOBJREC vrec;
245         TRAYREC tr_rec;
246         WEVENT paste_ev;
247         SEL_RGN sel;
248         RECT r0, vframe;
249
250         if (bchanl->currentsubject == NULL) {
251                 return;
252         }
253         draw = bchanl_subject_getdraw(bchanl->currentsubject);
254
255         err = sbjtdraw_findthread(draw, evpos, &tuple, &vframe);
256         if (err == 0) {
257                 return;
258         }
259
260         gid = subjectwindow_startdrag(bchanl->subjectwindow);
261         if (gid < 0) {
262                 DP_ER("wsta_drg error:", gid);
263                 return;
264         }
265
266         gget_fra(gid, &r0);
267         gset_vis(gid, r0);
268
269         dx = vframe.c.left - evpos.x;
270         dy = vframe.c.top - evpos.y;
271
272         p1 = evpos;
273         sel.sts = 0;
274         sel.rgn.r.c.left = vframe.c.left;
275         sel.rgn.r.c.top = vframe.c.top;
276         sel.rgn.r.c.right = vframe.c.right;
277         sel.rgn.r.c.bottom = vframe.c.bottom;
278         adsp_sel(gid, &sel, 1);
279
280         gset_ptr(PS_GRIP, NULL, -1, -1);
281         for (;;) {
282                 event_type = subjectwindow_getdrag(bchanl->subjectwindow, &pos, &wid_butup, &pos_butup);
283                 if (event_type == EV_BUTUP) {
284                         break;
285                 }
286                 if (event_type != EV_NULL) {
287                         continue;
288                 }
289                 if ((pos.x == p1.x)&&(pos.y == p1.y)) {
290                         continue;
291                 }
292                 adsp_sel(gid, &sel, 0);
293                 sel.rgn.r.c.left += pos.x - p1.x;
294                 sel.rgn.r.c.top += pos.y - p1.y;
295                 sel.rgn.r.c.right += pos.x - p1.x;
296                 sel.rgn.r.c.bottom += pos.y - p1.y;
297                 adsp_sel(gid, &sel, 1);
298                 p1 = pos;
299         }
300         gset_ptr(PS_SELECT, NULL, -1, -1);
301         adsp_sel(gid, &sel, 0);
302         subjectwindow_enddrag(bchanl->subjectwindow);
303
304         /* BUTUP on self window or no window or system message panel */
305         if ((wid_butup == subjectwindow_getWID(bchanl->subjectwindow))||(wid_butup == 0)||(wid_butup == -1)) {
306                 return;
307         }
308
309         err = oget_vob(-wid_butup, &vrec.vlnk, NULL, 0, &size);
310         if (err < 0) {
311                 return;
312         }
313
314         err = dget_dtp(64, BCHANL_DBX_VIEWER_FUSEN, (void**)&fsn);
315         if (err < 0) {
316                 DP_ER("dget_dtp: ", err);
317                 return;
318         }
319         fsn_len = dget_siz((B*)fsn);
320         err = bchanl_subject_createviewervobj(bchanl->currentsubject, tuple, fsn, fsn_len, &vrec.vseg, (LINK*)&vrec.vlnk);
321         if (err < 0) {
322                 DP_ER("bchanl_subject_createviewervobj error", err);
323                 return;
324         }
325         if (err == BCHANL_SUBJECT_CREATEVIEWERVOBJ_CANCELED) {
326                 DP(("canceled\n"));
327                 return;
328         }
329
330         tr_rec.id = TR_VOBJ;
331         tr_rec.len = sizeof(TR_VOBJREC);
332         tr_rec.dt = (B*)&vrec;
333         err = tset_dat(&tr_rec, 1);
334         if (err < 0) {
335                 err = del_fil(NULL, (LINK*)&vrec.vlnk, 0);
336                 if (err < 0) {
337                         DP_ER("error del_fil:", err);
338                 }
339                 return;
340         }
341
342         paste_ev.r.type = EV_REQUEST;
343         paste_ev.r.r.p.rightbot.x = pos_butup.x + dx;
344         paste_ev.r.r.p.rightbot.y = pos_butup.y + dy;
345         paste_ev.r.cmd = W_PASTE;
346         paste_ev.r.wid = wid_butup;
347         err = wsnd_evt(&paste_ev);
348         if (err < 0) {
349                 tset_dat(NULL, 0);
350                 err = del_fil(NULL, (LINK*)&vrec.vlnk, 0);
351                 if (err < 0) {
352                         DP_ER("error del_fil:", err);
353                 }
354                 return;
355         }
356         err = wwai_rsp(NULL, W_PASTE, 60000);
357         if (err != W_ACK) {
358                 tset_dat(NULL, 0);
359                 err = del_fil(NULL, (LINK*)&vrec.vlnk, 0);
360                 if (err < 0) {
361                         DP_ER("error del_fil:", err);
362                 }
363         }
364
365         wswi_wnd(wid_butup, NULL);
366 }
367
368 LOCAL VOID bchanl_subjectwindow_butdn(bchanl_t *bchanl, W dck, PNT evpos)
369 {
370         switch (dck) {
371         case    W_CLICK:
372         case    W_DCLICK:
373         case    W_QPRESS:
374         default:
375                 return;
376         case    W_PRESS:
377                 bchanl_subjectwindow_press(bchanl, evpos);
378         }
379 }
380
381 LOCAL VOID bchanl_setcurrentsubject(bchanl_t *bchanl, bchanl_subject_t *sbjt)
382 {
383         bchanl->currentsubject = sbjt;
384         subjectwindow_requestredisp(bchanl->subjectwindow);
385 }
386
387 LOCAL VOID bchanl_bbsmenuwindow_draw(bchanl_t *bchanl)
388 {
389         RECT r;
390         do {
391                 if (bbsmenuwindow_startredisp(bchanl->bbsmenuwindow, &r) == 0) {
392                         break;
393                 }
394                 bbsmenuwindow_eraseworkarea(bchanl->bbsmenuwindow, &r);
395                 bbsmndraw_draw(bchanl->bbsmenu.draw, &r);
396         } while (bbsmenuwindow_endredisp(bchanl->bbsmenuwindow) > 0);
397 }
398
399 LOCAL VOID bchanl_bbsmenuwindow_scroll(bchanl_t *bchanl, W dh, W dv)
400 {
401         bbsmndraw_scrollviewrect(bchanl->bbsmenu.draw, dh, dv);
402         bbsmenuwindow_scrollworkarea(bchanl->bbsmenuwindow, -dh, -dv);
403         bchanl_bbsmenuwindow_draw(bchanl);
404 }
405
406 LOCAL VOID bchanl_bbsmenuwindow_resize(bchanl_t *bchanl, SIZE newsize)
407 {
408         W l,t,r,b;
409
410         bbsmndraw_getviewrect(bchanl->bbsmenu.draw, &l, &t, &r, &b);
411
412         r = l + newsize.h;
413         b = t + newsize.v;
414
415         bbsmndraw_setviewrect(bchanl->bbsmenu.draw, l, t, r, b);
416         bbsmenuwindow_setworkrect(bchanl->bbsmenuwindow, l, t, r, b);
417
418         bchanl_bbsmenuwindow_draw(bchanl);
419 }
420
421 LOCAL VOID bchanl_bbsmenuwindow_close(bchanl_t *bchanl)
422 {
423         bchanl_killme(bchanl);
424 }
425
426 LOCAL VOID bchanl_updatesubjectorder(bchanl_t *bchanl, SUBJECTOPTIONWINDOW_ORDERVALUE_T order, SUBJECTOPTIONWINDOW_ORDERBYVALUE_T orderby, TC *filterword, W filterword_len)
427 {
428         Bool descending;
429         W sbjt_orderby;
430
431         if (order == SUBJECTOPTIONWINDOW_ORDERVALUE_DESCENDING) {
432                 descending = True;
433         } else {
434                 descending = False;
435         }
436         switch (orderby) {
437         case SUBJECTOPTIONWINDOW_ORDERBYVALUE_NUMBER:
438         default:
439                 sbjt_orderby = BCHANL_SUBJECT_SORTBY_NUMBER;
440                 break;
441         case SUBJECTOPTIONWINDOW_ORDERBYVALUE_RES:
442                 sbjt_orderby = BCHANL_SUBJECT_SORTBY_RES;
443                 break;
444         case SUBJECTOPTIONWINDOW_ORDERBYVALUE_SINCE:
445                 sbjt_orderby = BCHANL_SUBJECT_SORTBY_SINCE;
446                 break;
447         case SUBJECTOPTIONWINDOW_ORDERBYVALUE_VIGOR:
448                 sbjt_orderby = BCHANL_SUBJECT_SORTBY_VIGOR;
449                 break;
450         }
451
452         bchanl_subject_reorder(bchanl->currentsubject, filterword, filterword_len, sbjt_orderby, descending);
453
454         subjectwindow_requestredisp(bchanl->subjectwindow);
455 }
456
457 LOCAL VOID bchanl_changesubjectorder(bchanl_t *bchanl, W neworder)
458 {
459         SUBJECTOPTIONWINDOW_ORDERBYVALUE_T orderby;
460         W len;
461         TC buf[512];
462
463         if (bchanl->currentsubject == NULL) {
464                 return;
465         }
466
467         subjectoptionwindow_getorderbyvalue(bchanl->subjectoptionwindow, &orderby);
468         len = subjectoptionwindow_getfiltertext(bchanl->subjectoptionwindow, buf, 512);
469
470         bchanl_updatesubjectorder(bchanl, neworder, orderby, buf, len);
471 }
472
473 LOCAL VOID bchanl_changesubjectorderby(bchanl_t *bchanl, W neworderby)
474 {
475         SUBJECTOPTIONWINDOW_ORDERBYVALUE_T order;
476         W len;
477         TC buf[512];
478
479         if (bchanl->currentsubject == NULL) {
480                 return;
481         }
482
483         subjectoptionwindow_getordervalue(bchanl->subjectoptionwindow, &order);
484         len = subjectoptionwindow_getfiltertext(bchanl->subjectoptionwindow, buf, 512);
485
486         bchanl_updatesubjectorder(bchanl, order, neworderby, buf, len);
487 }
488
489 LOCAL VOID bchanl_changesubjectfilterword(bchanl_t *bchanl, TC *newstr, W newstr_len)
490 {
491         sbjtlayout_t *layout;
492         sbjtdraw_t *draw;
493         SUBJECTOPTIONWINDOW_ORDERVALUE_T order;
494         SUBJECTOPTIONWINDOW_ORDERBYVALUE_T orderby;
495         RECT w_work;
496         W l, t, r, b;
497
498         if (bchanl->currentsubject == NULL) {
499                 return;
500         }
501
502         subjectoptionwindow_getordervalue(bchanl->subjectoptionwindow, &order);
503         subjectoptionwindow_getorderbyvalue(bchanl->subjectoptionwindow, &orderby);
504
505         bchanl_updatesubjectorder(bchanl, order, orderby, newstr, newstr_len);
506
507         subjectwindow_getworkrect(bchanl->subjectwindow, &w_work);
508         draw = bchanl_subject_getdraw(bchanl->currentsubject);
509         sbjtdraw_setviewrect(draw, 0, 0, w_work.c.right, w_work.c.bottom);
510         subjectwindow_setworkrect(bchanl->subjectwindow, 0, 0, w_work.c.right, w_work.c.bottom);
511
512         layout = bchanl_subject_getlayout(bchanl->currentsubject);
513         sbjtlayout_getdrawrect(layout, &l, &t, &r, &b);
514         subjectwindow_setdrawrect(bchanl->subjectwindow, l, t, r, b);
515 }
516
517 LOCAL VOID bchanl_sendsubjectrequest(bchanl_t *bchanl, bchanl_subject_t *subject)
518 {
519         sbjtcache_t *cache;
520         sbjtlayout_t *layout;
521         sbjtdraw_t *draw;
522         TC *title;
523         RECT w_work;
524         W l, t, r, b, title_len, err;
525
526         bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_BUSY);
527         pdsp_msg(bchanl->hmistate.msg_retr_subject);
528
529         cache = bchanl_subject_getcache(subject);
530         err = sbjtretriever_sendrequest(bchanl->retriever, cache);
531         if (err < 0) {
532                 pdsp_msg(bchanl->hmistate.msg_error_retr);
533                 bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_SELECT);
534                 return;
535         }
536
537         pdsp_msg(NULL);
538         bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_SELECT);
539
540         subjectoptionwindow_setfiltertext(bchanl->subjectoptionwindow, NULL, 0);
541         err = subjectoptionwindow_setordervalue(bchanl->subjectoptionwindow, SUBJECTOPTIONWINDOW_ORDERVALUE_ASCENDING);
542         subjectoptionwindow_setorderbyvalue(bchanl->subjectoptionwindow, SUBJECTOPTIONWINDOW_ORDERBYVALUE_NUMBER);
543
544         bchanl_subject_relayout(subject);
545
546         bchanl_setcurrentsubject(bchanl, subject);
547
548         subjectwindow_getworkrect(bchanl->subjectwindow, &w_work);
549         draw = bchanl_subject_getdraw(subject);
550         sbjtdraw_setviewrect(draw, 0, 0, w_work.c.right, w_work.c.bottom);
551         subjectwindow_setworkrect(bchanl->subjectwindow, 0, 0, w_work.c.right, w_work.c.bottom);
552
553         layout = bchanl_subject_getlayout(subject);
554         sbjtlayout_getdrawrect(layout, &l, &t, &r, &b);
555         subjectwindow_setdrawrect(bchanl->subjectwindow, l, t, r, b);
556
557         bchanl_subject_gettitle(subject, &title, &title_len);
558         subjectwindow_settitle(bchanl->subjectwindow, title);
559 }
560
561 LOCAL VOID bchanl_bbsmenuwindow_click(bchanl_t *bchanl, PNT pos)
562 {
563         bbsmnparser_item_t *item;
564         bchanl_subject_t *subject;
565         W fnd;
566         UB *host, *board;
567         W host_len, board_len;
568         TC *title;
569         W title_len;
570
571         fnd = bbsmndraw_findboard(bchanl->bbsmenu.draw, pos, &item);
572         if (fnd == 0) {
573                 DP(("not found\n"));
574                 return;
575         }
576         if (item->category != NULL) {
577                 return;
578         }
579         bbsmnparser_item_gethostboard(item, &host, &host_len, &board, &board_len);
580         subject = bchanl_subjecthash_search(bchanl->subjecthash, host, host_len, board, board_len);
581         if (subject == NULL) {
582                 DP(("not found by subject hash"));
583                 return;
584         }
585         bchanl_subject_gettitle(subject, &title, &title_len);
586
587         bchanl_sendsubjectrequest(bchanl, subject);
588 }
589
590 LOCAL VOID bchanl_bbsmenuwindow_butdn(bchanl_t *bchanl, W dck, PNT evpos)
591 {
592         switch (dck) {
593         case    W_DCLICK:
594         case    W_PRESS:
595         case    W_QPRESS:
596         default:
597                 return;
598         case    W_CLICK:
599                 bchanl_bbsmenuwindow_click(bchanl, evpos);
600         }
601 }
602
603 LOCAL W bchanl_bbsmenu_initialize(bchanl_bbsmenu_t *bchanl, GID gid, bchanl_subjecthash_t *subjecthash, LINK *storage)
604 {
605         bbsmnretriever_t *retriever;
606         bbsmncache_t *cache;
607         bbsmnparser_t *parser;
608         bbsmnfilter_t *filter;
609         bbsmnlayout_t *layout;
610         bbsmndraw_t *draw;
611         extbbslist_t *extbbslist;
612         TC *category_extbbs;
613
614         cache = bbsmncache_new();
615         if (cache == NULL) {
616                 goto error_cache;
617         }
618         retriever = bbsmnretriever_new();
619         if (retriever == NULL) {
620                 goto error_retriever;
621         }
622         parser = bbsmnparser_new(cache);
623         if (parser == NULL) {
624                 goto error_parser;
625         }
626         filter = bbsmnfilter_new();
627         if (filter == NULL) {
628                 goto error_filter;
629         }
630         layout = bbsmnlayout_new(gid);
631         if (layout == NULL) {
632                 goto error_layout;
633         }
634         draw = bbsmndraw_new(layout);
635         if (draw == NULL) {
636                 goto error_draw;
637         }
638         extbbslist = extbbslist_new(storage, BCHANL_COMMONSTORAGE_EXTBBSLIST_RECTYPE, BCHANL_COMMONSTORAGE_EXTBBSLIST_SUBTYPE);
639         if (extbbslist == NULL) {
640                 DP_ER("extbbslist_new", 0);
641                 goto error_extbbslist;
642         }
643         dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_CATE_EXTBBS, (void**)&category_extbbs);
644
645         bchanl->gid = gid;
646         bchanl->retriever = retriever;
647         bchanl->cache = cache;
648         bchanl->parser = parser;
649         bchanl->filter = filter;
650         bchanl->layout = layout;
651         bchanl->draw = draw;
652         bchanl->subjecthash = subjecthash;
653         bchanl->extbbslist = extbbslist;
654         bchanl->editctx = NULL;
655         bchanl->category_extbbs = category_extbbs;
656
657         return 0;
658
659 error_extbbslist:
660         bbsmndraw_delete(draw);
661 error_draw:
662         bbsmnlayout_delete(layout);
663 error_layout:
664         bbsmnfilter_delete(filter);
665 error_filter:
666         bbsmnparser_delete(parser);
667 error_parser:
668         bbsmnretriever_delete(retriever);
669 error_retriever:
670         bbsmncache_delete(cache);
671 error_cache:
672         return -1; /* TODO */
673 }
674
675 LOCAL W bchanl_bbsmenu_appenditemtohash(bchanl_bbsmenu_t *bchanl, bbsmnparser_item_t *item)
676 {
677         W err;
678         UB *host, *board;
679         W host_len, board_len;
680
681         bbsmnparser_item_gethostboard(item, &host, &host_len, &board, &board_len);
682         err = bchanl_subjecthash_append(bchanl->subjecthash, host, host_len, board, board_len, item->title, item->title_len);
683         return err;
684 }
685
686 LOCAL VOID bchanl_bbsmenu_registerexternalbbs(bchanl_bbsmenu_t *bchanl, TC *title, W title_len, TC *url, W url_len)
687 {
688         extbbslist_editcontext_append(bchanl->editctx, title, title_len, url, url_len);
689 }
690
691 LOCAL VOID bchanl_bbsmenu_relayoutcache(bchanl_bbsmenu_t *bchanl)
692 {
693         W err, ret;
694         bbsmnparser_t *parser = bchanl->parser;
695         bbsmnparser_item_t *item;
696         bbsmnfilter_t *filter = bchanl->filter;
697         bbsmnlayout_t *layout = bchanl->layout;
698
699         for (;;) {
700                 err = bbsmnparser_getnextitem(parser, &item);
701                 if (err != 1) {
702                         break;
703                 }
704                 bbsmnfilter_inputitem(filter, item);
705                 for (;;) {
706                         ret = bbsmnfilter_outputitem(filter, &item);
707                         if (item != NULL) {
708                                 if (item->category == NULL) {
709                                         err = bchanl_bbsmenu_appenditemtohash(bchanl, item);
710                                         if (err < 0) {
711                                                 return;
712                                         }
713                                 }
714                                 err = bbsmnlayout_appenditem(layout, item);
715                                 if (err < 0) {
716                                         return;
717                                 }
718                         }
719                         if (ret != BBSMNFILTER_OUTPUTITEM_CONTINUE) {
720                                 break;
721                         }
722                 }
723                 if (ret == BBSMNFILTER_OUTPUTITEM_END) {
724                         printf("D\n");
725                         break;
726                 }
727                 if (ret != BBSMNFILTER_OUTPUTITEM_WAITNEXT) {
728                         /* TODO: error */
729                         break;
730                 }
731 /*
732                 if (item == NULL) {
733                         printf("F\n");
734                         break;
735                 }
736 */
737         }
738 }
739
740 LOCAL VOID bchanl_bbsmenu_relayoutexternal(bchanl_bbsmenu_t *bchanl)
741 {
742         W err, ret, category_len, title_len, url_len;
743         Bool cont;
744         TC *category, *title;
745         UB *url;
746         extbbslist_readcontext_t *ctx;
747         bbsmnparser_t *parser = bchanl->parser;
748         bbsmnparser_item_t *item;
749         bbsmnlayout_t *layout = bchanl->layout;
750         extbbslist_t *list = bchanl->extbbslist;
751
752         ret = extbbslist_number(bchanl->extbbslist);
753         if (ret <= 0) {
754                 return;
755         }
756
757         category = bchanl->category_extbbs;
758         category_len = tc_strlen(category);
759         item = bbsmnparser_newcategoryitem(parser, category, category_len);
760         if (item == NULL) {
761                 return;
762         }
763         err = bbsmnlayout_appenditem(layout, item);
764         if (err < 0) {
765                 return;
766         }
767
768         ctx = extbbslist_startread(list);
769         if (ctx == NULL) {
770                 return;
771         }
772         for (;;) {
773                 cont = extbbslist_readcontext_getnext(ctx, &title, &title_len, &url, &url_len);
774                 if (cont == False) {
775                         break;
776                 }
777
778                 item = bbsmnparser_newboarditem(parser, title, title_len, url, url_len);
779                 if (item == NULL) {
780                         break;
781                 }
782                 err = bchanl_bbsmenu_appenditemtohash(bchanl, item);
783                 if (err < 0) {
784                         break;
785                 }
786                 err = bbsmnlayout_appenditem(layout, item);
787                 if (err < 0) {
788                         break;
789                 }
790         }
791         extbbslist_endread(list, ctx);
792 }
793
794 LOCAL VOID bchanl_bbsmenu_relayout(bchanl_bbsmenu_t *bchanl, bbsmenuwindow_t *window)
795 {
796         W l, t, r, b;
797
798         bbsmnlayout_clear(bchanl->layout);
799         bbsmnfilter_clear(bchanl->filter);
800         bbsmnparser_clear(bchanl->parser);
801
802         bchanl_bbsmenu_relayoutcache(bchanl);
803         bchanl_bbsmenu_relayoutexternal(bchanl);
804
805         bbsmnlayout_getdrawrect(bchanl->layout, &l, &t, &r, &b);
806         bbsmenuwindow_setdrawrect(window, l, t, r, b);
807
808         bbsmenuwindow_requestredisp(window);
809 }
810
811 LOCAL Bool bchanl_registerexternalbbs(bchanl_t *bchanl)
812 {
813         TC title[128];
814         TC url[256];
815         W title_len, url_len;
816         TCURL_CHECK_VALID_BBSURL ret;
817
818         title_len = registerexternalwindow_getboradnametext(bchanl->registerexternalwindow, title, 128);
819         if (title_len < 0) {
820                 DP_ER("registerexternalwindow_getboradnametext error", title_len);
821                 return True;
822         }
823         title[title_len] = TNULL;
824         url_len = registerexternalwindow_geturltext(bchanl->registerexternalwindow, url, 255);
825         if (url_len < 0) {
826                 DP_ER("registerexternalwindow_geturltext error", url_len);
827                 return True;
828         }
829         url[url_len] = TNULL;
830
831         ret = tcurl_check_valid_bbsurl(url, url_len);
832         switch (ret) {
833           case TCURL_CHECK_VALID_BBSURL_NO_LAST_SLSH:
834                 url[url_len+1] = TK_SLSH;
835                 url_len++;
836                 /* intentional */
837           case TCURL_CHECK_VALID_BBSURL_OK:
838                 break;
839           case TCURL_CHECK_VALID_BBSURL_INVALID_SCHEME:
840                 bchan_panels_urlerror_scheme();
841                 return False;
842           case TCURL_CHECK_VALID_BBSURL_INVALID_HOST:
843                 bchan_panels_urlerror_host();
844                 return False;
845           case TCURL_CHECK_VALID_BBSURL_INVALID_PATH:
846                 bchan_panels_urlerror_path();
847                 return False;
848         }
849
850         bchanl_bbsmenu_registerexternalbbs(&bchanl->bbsmenu, title, title_len, url, url_len);
851
852         registerexternalwindow_setboradnametext(bchanl->registerexternalwindow, NULL, 0);
853         registerexternalwindow_seturltext(bchanl->registerexternalwindow, NULL, 0);
854
855         externalbbswindow_requestredisp(bchanl->externalbbswindow);
856
857         return True;
858 }
859
860 LOCAL VOID bchanl_externalbbswindow_draw(bchanl_t *bchanl)
861 {
862         RECT r;
863
864         do {
865                 if (externalbbswindow_startredisp(bchanl->externalbbswindow, &r) == 0) {
866                         break;
867                 }
868                 externalbbswindow_eraseworkarea(bchanl->externalbbswindow, &r);
869                 extbbslist_editcontext_draw(bchanl->bbsmenu.editctx, externalbbswindow_getGID(bchanl->externalbbswindow), &r);
870         } while (externalbbswindow_endredisp(bchanl->externalbbswindow) > 0);
871 }
872
873 LOCAL VOID bchanl_externalbbswindow_resize(bchanl_t *bchanl, SIZE newsize)
874 {
875         W l,t,r,b;
876
877         extbbslist_editcontext_getviewrect(bchanl->bbsmenu.editctx, &l, &t, &r, &b);
878
879         r = l + newsize.h;
880         b = t + newsize.v;
881
882         extbbslist_editcontext_setviewrect(bchanl->bbsmenu.editctx, l, t, r, b);
883         externalbbswindow_setworkrect(bchanl->externalbbswindow, l, t, r, b);
884 }
885
886 LOCAL VOID bchanl_externalbbswindow_close(bchanl_t *bchanl)
887 {
888         Bool changed, save = False;
889         BCHAN_PANELS_SAVECONFIRM_RESULT confirm;
890
891         changed = extbbslist_editcontext_ischanged(bchanl->bbsmenu.editctx);
892         if (changed != False) {
893                 confirm = bchan_panels_saveconfirm();
894                 switch (confirm) {
895                 case BCHAN_PANELS_SAVECONFIRM_RESULT_CANCEL:
896                         return;
897                 case BCHAN_PANELS_SAVECONFIRM_RESULT_OK_NOSAVE:
898                         save = False;
899                         break;
900                 case BCHAN_PANELS_SAVECONFIRM_RESULT_OK_SAVE:
901                         save = True;
902                         break;
903                 default:
904                         break;
905                 }
906         }
907
908         extbbslist_endedit(bchanl->bbsmenu.extbbslist, bchanl->bbsmenu.editctx, save);
909         bchanl->bbsmenu.editctx = NULL;
910         externalbbswindow_close(bchanl->externalbbswindow);
911         if (save != False) {
912                 bchanl_bbsmenu_relayout(&bchanl->bbsmenu, bchanl->bbsmenuwindow);
913         }
914 }
915
916 LOCAL VOID bchanl_externalbbswindow_butdn(bchanl_t *bchanl, W type, PNT pos)
917 {
918         Bool found;
919         W sel;
920
921         if (type == W_CLICK) {
922                 found = extbbslist_editcontext_finditem(bchanl->bbsmenu.editctx, pos, &sel);
923                 if (found != False) {
924                         extbbslist_editcontext_setselect(bchanl->bbsmenu.editctx, sel);
925                 }
926                 externalbbswindow_requestredisp(bchanl->externalbbswindow);
927         }
928 }
929
930 LOCAL VOID bchanl_externalbbswindow_paste(bchanl_t *bchanl)
931 {
932         externalbbswindow_responsepasterequest(bchanl->externalbbswindow, /* NACK */ 1, NULL);
933 }
934
935 LOCAL VOID bchanl_externalbbswindow_scroll(bchanl_t *bchanl, W dh, W dv)
936 {
937         extbbslist_editcontext_scrollviewrect(bchanl->bbsmenu.editctx, dh, dv);
938         externalbbswindow_scrollworkarea(bchanl->externalbbswindow, -dh, -dv);
939 }
940
941 #define BCHANL_MESSAGE_RETRIEVER_RELAYOUT 1
942 #define BCHANL_MESSAGE_RETRIEVER_ERROR -1
943
944 LOCAL VOID bchanl_retriever_task(W arg)
945 {
946         bchanl_t *bchanl;
947         bbsmnretriever_t *retr;
948         bbsmncache_t *cache;
949         W msg,err;
950
951         bchanl = (bchanl_t*)arg;
952         retr = bchanl->bbsmenu.retriever;
953         cache = bchanl->bbsmenu.cache;
954
955         for (;;) {
956                 DP(("before rcv_mbf %d\n", bchanl->mbfid));
957                 err = rcv_mbf(bchanl->mbfid, (VP)&msg, T_FOREVER);
958                 DP_ER("rcv_mbf error:",err);
959                 if (err != 4) {
960                         continue;
961                 }
962
963                 err = bbsmnretriever_sendrequest(retr, cache);
964
965                 switch (err) {
966                 case BBSMNRETRIEVER_REQUEST_ALLRELOAD:
967                         req_tmg(0, BCHANL_MESSAGE_RETRIEVER_RELAYOUT);
968                         break;
969                 default:
970                         req_tmg(0, BCHANL_MESSAGE_RETRIEVER_ERROR);
971                         DP_ER("bbsmnretreiver_request error",err);
972                         break;
973                 }
974         }
975
976         ext_tsk();
977 }
978
979 LOCAL W bchanl_prepare_network(bchanl_t *bchanl)
980 {
981         if (bchanl->retriever == NULL) {
982                 return 0;
983         }
984
985         bchanl->mbfid = cre_mbf(sizeof(W), sizeof(W), DELEXIT);
986         if (bchanl->mbfid < 0) {
987                 DP_ER("error cre_mbf:", bchanl->mbfid);
988                 return -1;
989         }
990         bchanl->taskid = cre_tsk(bchanl_retriever_task, -1, (W)bchanl);
991         if (bchanl->taskid < 0) {
992                 del_mbf(bchanl->mbfid);
993                 bchanl->mbfid = -1;
994                 DP_ER("error cre_tsk:", bchanl->taskid);
995                 return -1;
996         }
997
998         return 0;
999 }
1000
1001 LOCAL W bchanl_networkrequest_bbsmenu(bchanl_t *bchanl)
1002 {
1003         W msg = 1, err;
1004         static UW lastrequest = 0;
1005         UW etime;
1006
1007         if (bchanl->mbfid < 0) {
1008                 return 0;
1009         }
1010
1011         err = get_etm(&etime);
1012         if (err < 0) {
1013                 DP_ER("get_etm error:", err);
1014                 return err;
1015         }
1016         if (lastrequest + 10000 > etime) {
1017                 return 0;
1018         }
1019         lastrequest = etime;
1020
1021         err = snd_mbf(bchanl->mbfid, &msg, sizeof(W), T_FOREVER);
1022         if (err < 0) {
1023                 DP_ER("snd_mbf error:", err);
1024                 return err;
1025         }
1026
1027         bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_BUSY);
1028         pdsp_msg(bchanl->hmistate.msg_retr_bbsmenu);
1029
1030         return 0;
1031 }
1032
1033 LOCAL W bchanl_initialize(bchanl_t *bchanl, VID vid, W exectype, LINK *storage)
1034 {
1035         static  RECT    r0 = {{400, 100, 700+7, 200+30}};
1036         static  RECT    r1 = {{100, 100, 300+7, 300+30}};
1037         static  RECT    r2 = {{400, 300, 800+7, 400+30}};
1038         TC *title0 = NULL, *title1 = NULL;
1039         W err;
1040         WID wid;
1041         GID gid;
1042         RECT w_work;
1043         PNT p0 = {450, 0};
1044         sbjtretriever_t *retriever;
1045         bchanlhmi_t *hmi;
1046         bchanl_subjecthash_t *subjecthash;
1047         subjectwindow_t *subjectwindow;
1048         bbsmenuwindow_t *bbsmenuwindow;
1049         subjectoptionwindow_t *subjectoptionwindow;
1050         registerexternalwindow_t *registerexternalwindow;
1051         externalbbswindow_t *externalbbswindow;
1052
1053         retriever = sbjtretriever_new();
1054         if (retriever == NULL) {
1055                 DP_ER("sbjtretriever_new error", 0);
1056                 goto error_retriever;
1057         }
1058         hmi = bchanlhmi_new();
1059         if (hmi == NULL) {
1060                 DP_ER("bchanlhmi_new error", 0);
1061                 goto error_bchanlhmi;
1062         }
1063         dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_WINDOWTITLE_SUBJECT, (void**)&title0);
1064         subjectwindow = bchanlhmi_newsubjectwindow(hmi, &r0, 0, title0, NULL);
1065         if (subjectwindow == NULL) {
1066                 DP_ER("bchanlhmi_newsubjectwindow error", 0);
1067                 goto error_subjectwindow;
1068         }
1069         gid = subjectwindow_getGID(subjectwindow);
1070         subjecthash = bchanl_subjecthash_new(gid, 100);
1071         if (subjecthash == NULL) {
1072                 DP_ER("bchanl_subjecthash_new error", 0);
1073                 goto error_subjecthash;
1074         }
1075         subjectoptionwindow = bchanlhmi_newsubjectoptionwindow(hmi, &p0, subjectwindow, NULL, NULL, BCHANL_DBX_TB_SBJTOPT_FLT, BCHANL_DBX_WS_SBJTOPT_ODR, BCHANL_DBX_WS_SBJTOPT_ODRBY);
1076         if (subjectoptionwindow == NULL) {
1077                 DP_ER("bchanlhmi_newsubjectoptionwindow", 0);
1078                 goto error_subjectoptionwindow;
1079         }
1080         dget_dtp(TEXT_DATA, BCHANL_DBX_TEXT_WINDOWTITLE_BBSMENU, (void**)&title1);
1081         bbsmenuwindow = bchanlhmi_newbbsmenuwindow(hmi, &r1, 0, title1, NULL);
1082         if (bbsmenuwindow == NULL) {
1083                 DP_ER("bchanlhmi_newbbsmenuwindow error", 0);
1084                 goto error_bbsmenuwindow;
1085         }
1086         gid = bbsmenuwindow_getGID(bbsmenuwindow);
1087         registerexternalwindow = bchanlhmi_newregisterexternalwindow(hmi, &p0, 0, NULL, NULL);
1088         if (registerexternalwindow == NULL) {
1089                 DP_ER("bchanlhmi_newregisterexternalwindow error", 0);
1090                 goto error_registerexternalwindow;
1091         }
1092         externalbbswindow = bchanlhmi_newexternalbbswindow(hmi, &r2, 0, NULL, NULL);
1093         if (externalbbswindow == NULL) {
1094                 DP_ER("bchanlhmi_newexternalbbswindow", 0);
1095                 goto error_externalbbswindow;
1096         }
1097         err = bchanl_bbsmenu_initialize(&(bchanl->bbsmenu), gid, subjecthash, storage);
1098         if (err < 0) {
1099                 DP_ER("bchanl_bbsmenu_initialize error", err);
1100                 goto error_bbsmenu;
1101         }
1102         err = bchanl_mainmenu_initialize(&(bchanl->mainmenu), BCHANL_DBX_MENU_TEST);
1103         if (err < 0) {
1104                 DP_ER("bchanl_mainmenu_initialize %d", err);
1105                 goto error_mainmenu;
1106         }
1107
1108         bchanl_hmistate_initialize(&bchanl->hmistate);
1109
1110         if (exectype == EXECREQ) {
1111                 wid = bbsmenuwindow_getWID(bbsmenuwindow);
1112                 osta_prc(vid, wid);
1113         }
1114
1115         bbsmenuwindow_getworkrect(bbsmenuwindow, &w_work);
1116         bbsmndraw_setviewrect(bchanl->bbsmenu.draw, 0, 0, w_work.c.right, w_work.c.bottom);
1117         bbsmenuwindow_setworkrect(bbsmenuwindow, 0, 0, w_work.c.right, w_work.c.bottom);
1118
1119         bchanl->retriever = retriever;
1120         bchanl->subjecthash = subjecthash;
1121
1122         bchanl->currentsubject = NULL;
1123
1124         bchanl->vid = vid;
1125         bchanl->exectype = exectype;
1126
1127         bchanl->hmi = hmi;
1128         bchanl->subjectwindow = subjectwindow;
1129         bchanl->bbsmenuwindow = bbsmenuwindow;
1130         bchanl->subjectoptionwindow = subjectoptionwindow;
1131         bchanl->registerexternalwindow = registerexternalwindow;
1132         bchanl->externalbbswindow = externalbbswindow;
1133
1134         return 0;
1135
1136 error_mainmenu:
1137         //bchanl_bbsmenu_finalize(&(bchanl->bbsmenu));
1138 error_bbsmenu:
1139         bchanlhmi_deleteexternalbbswindow(hmi, externalbbswindow);
1140 error_externalbbswindow:
1141         bchanlhmi_deleteregisterexternalwindow(hmi, registerexternalwindow);
1142 error_registerexternalwindow:
1143         bchanlhmi_deletebbsmenuwindow(hmi, bbsmenuwindow);
1144 error_bbsmenuwindow:
1145         bchanlhmi_deletesubjectoptionwindow(hmi, subjectoptionwindow);
1146 error_subjectoptionwindow:
1147         bchanl_subjecthash_delete(subjecthash);
1148 error_subjecthash:
1149         bchanlhmi_deletesubjectwindow(hmi, subjectwindow);
1150 error_subjectwindow:
1151         bchanlhmi_delete(hmi);
1152 error_bchanlhmi:
1153         sbjtretriever_delete(retriever);
1154 error_retriever:
1155         return -1; /* TODO */
1156 }
1157
1158 LOCAL VOID bchanl_killme(bchanl_t *bchanl)
1159 {
1160         gset_ptr(PS_BUSY, NULL, -1, -1);
1161         pdsp_msg(NULL);
1162
1163         if (bchanl->exectype == EXECREQ) {
1164                 oend_prc(bchanl->vid, NULL, 0);
1165         }
1166         bchanl_mainmenu_finalize(&bchanl->mainmenu);
1167         bchanlhmi_deleteexternalbbswindow(bchanl->hmi, bchanl->externalbbswindow);
1168         bchanlhmi_deleteregisterexternalwindow(bchanl->hmi, bchanl->registerexternalwindow);
1169         bchanlhmi_deletebbsmenuwindow(bchanl->hmi, bchanl->bbsmenuwindow);
1170         bchanlhmi_deletesubjectoptionwindow(bchanl->hmi, bchanl->subjectoptionwindow);
1171         bchanl_subjecthash_delete(bchanl->subjecthash);
1172         bchanlhmi_deletesubjectwindow(bchanl->hmi, bchanl->subjectwindow);
1173         bchanlhmi_delete(bchanl->hmi);
1174         sbjtretriever_delete(bchanl->retriever);
1175
1176         ext_prc(0);
1177 }
1178
1179 LOCAL VOID bchanl_readbbsmenutestdata(bchanl_bbsmenu_t *bchanl, bbsmenuwindow_t *bchanl_window)
1180 {
1181         TC fname[] = {TK_b, TK_b, TK_s, TK_m, TK_e, TK_n, TK_u, TK_PROD, TK_h, TK_t, TK_m, TK_l, TNULL};
1182         LINK lnk;
1183         W fd, len, err;
1184         UB *bin;
1185         RECT w_work;
1186         bbsmncache_t *cache = bchanl->cache;
1187         bbsmndraw_t *draw = bchanl->draw;
1188
1189         err = get_lnk(fname, &lnk, F_NORM);
1190         if (err < 0) {
1191                 DP_ER("error get_lnk", err);
1192                 return;
1193         }
1194         fd = opn_fil(&lnk, F_READ, NULL);
1195         if (fd < 0) {
1196                 return;
1197         }
1198         err = rea_rec(fd, 0, NULL, 0, &len, NULL);
1199         if (err < 0) {
1200                 cls_fil(fd);
1201                 return;
1202         }
1203         bin = malloc(len);
1204         if (bin == NULL) {
1205                 cls_fil(fd);
1206                 return;
1207         }
1208         err = rea_rec(fd, 0, bin, len, 0, NULL);
1209         if (err < 0) {
1210                 free(bin);
1211                 cls_fil(fd);
1212                 return;
1213         }
1214         cls_fil(fd);
1215
1216         bbsmncache_appenddata(cache, bin, len);
1217         free(bin);
1218
1219         req_tmg(0, BCHANL_MESSAGE_RETRIEVER_RELAYOUT);
1220
1221         bbsmenuwindow_getworkrect(bchanl_window, &w_work);
1222         bbsmndraw_setviewrect(draw, 0, 0, w_work.c.right, w_work.c.bottom);
1223         bbsmenuwindow_setworkrect(bchanl_window, 0, 0, w_work.c.right, w_work.c.bottom);
1224 }
1225
1226 LOCAL VOID bchanl_subjectwindow_keydwn(bchanl_t *bchanl, UH keycode, TC ch, UW stat)
1227 {
1228         W l,t,r,b,l1,t1,r1,b1,scr;
1229         sbjtlayout_t *layout;
1230         sbjtdraw_t *draw;
1231
1232         if (bchanl->currentsubject == NULL) {
1233                 return;
1234         }
1235         draw = bchanl_subject_getdraw(bchanl->currentsubject);
1236
1237         switch (ch) {
1238         case KC_CC_U:
1239                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1240                 if (t < 16) {
1241                         scr = -t;
1242                 } else {
1243                         scr = -16;
1244                 }
1245                 subjectwindow_scrollbyvalue(bchanl->subjectwindow, 0, scr);
1246                 bchanl_subjectwindow_scroll(bchanl, 0, scr);
1247                 break;
1248         case KC_CC_D:
1249                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1250                 layout = bchanl_subject_getlayout(bchanl->currentsubject);
1251                 sbjtlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1252                 if (b + 16 > b1) {
1253                         scr = b1 - b;
1254                 } else {
1255                         scr = 16;
1256                 }
1257                 if (scr > 0) {
1258                         subjectwindow_scrollbyvalue(bchanl->subjectwindow, 0, scr);
1259                         bchanl_subjectwindow_scroll(bchanl, 0, scr);
1260                 }
1261                 break;
1262         case KC_CC_R:
1263                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1264                 layout = bchanl_subject_getlayout(bchanl->currentsubject);
1265                 sbjtlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1266                 if (r + 16 > r1) {
1267                         scr = r1 - r;
1268                 } else {
1269                         scr = 16;
1270                 }
1271                 if (scr > 0) {
1272                         subjectwindow_scrollbyvalue(bchanl->subjectwindow, scr, 0);
1273                         bchanl_subjectwindow_scroll(bchanl, scr, 0);
1274                 }
1275                 break;
1276         case KC_CC_L:
1277                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1278                 if (l < 16) {
1279                         scr = -l;
1280                 } else {
1281                         scr = -16;
1282                 }
1283                 subjectwindow_scrollbyvalue(bchanl->subjectwindow, scr, 0);
1284                 bchanl_subjectwindow_scroll(bchanl, scr, 0);
1285                 break;
1286         case KC_PG_U:
1287                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1288                 if (t < (b - t)) {
1289                         scr = -t;
1290                 } else {
1291                         scr = - (b - t);
1292                 }
1293                 subjectwindow_scrollbyvalue(bchanl->subjectwindow, 0, scr);
1294                 bchanl_subjectwindow_scroll(bchanl, 0, scr);
1295                 break;
1296         case KC_PG_D:
1297                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1298                 layout = bchanl_subject_getlayout(bchanl->currentsubject);
1299                 sbjtlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1300                 if (b + (b - t) > b1) {
1301                         scr = b1 - b;
1302                 } else {
1303                         scr = (b - t);
1304                 }
1305                 if (scr > 0) {
1306                         subjectwindow_scrollbyvalue(bchanl->subjectwindow, 0, scr);
1307                         bchanl_subjectwindow_scroll(bchanl, 0, scr);
1308                 }
1309                 break;
1310         case KC_PG_R:
1311                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1312                 layout = bchanl_subject_getlayout(bchanl->currentsubject);
1313                 sbjtlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1314                 if (r + (r - l) > r1) {
1315                         scr = r1 - r;
1316                 } else {
1317                         scr = (r - l);
1318                 }
1319                 if (scr > 0) {
1320                         subjectwindow_scrollbyvalue(bchanl->subjectwindow, scr, 0);
1321                         bchanl_subjectwindow_scroll(bchanl, scr, 0);
1322                 }
1323                 break;
1324         case KC_PG_L:
1325                 sbjtdraw_getviewrect(draw, &l, &t, &r, &b);
1326                 if (l < (r - l)) {
1327                         scr = -l;
1328                 } else {
1329                         scr = - (r - l);
1330                 }
1331                 subjectwindow_scrollbyvalue(bchanl->subjectwindow, scr, 0);
1332                 bchanl_subjectwindow_scroll(bchanl, scr, 0);
1333                 break;
1334         case TK_E: /* temporary */
1335                 if (stat & ES_CMD) {
1336                         bchanl_killme(bchanl);
1337                 }
1338                 break;
1339         }
1340 }
1341
1342 LOCAL VOID bchanl_bbsmenuwindow_keydwn(bchanl_t *bchanl, UH keycode, TC ch, UW stat)
1343 {
1344         W l,t,r,b,l1,t1,r1,b1,scr;
1345         bbsmndraw_t *draw = bchanl->bbsmenu.draw;
1346         bbsmnlayout_t *layout = bchanl->bbsmenu.layout;
1347
1348         switch (ch) {
1349         case KC_CC_U:
1350                 bbsmndraw_getviewrect(draw, &l, &t, &r, &b);
1351                 if (t < 16) {
1352                         scr = -t;
1353                 } else {
1354                         scr = -16;
1355                 }
1356                 bbsmenuwindow_scrollbyvalue(bchanl->bbsmenuwindow, 0, scr);
1357                 bchanl_bbsmenuwindow_scroll(bchanl, 0, scr);
1358                 break;
1359         case KC_CC_D:
1360                 bbsmndraw_getviewrect(draw, &l, &t, &r, &b);
1361                 bbsmnlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1362                 if (b + 16 > b1) {
1363                         scr = b1 - b;
1364                 } else {
1365                         scr = 16;
1366                 }
1367                 if (scr > 0) {
1368                         bbsmenuwindow_scrollbyvalue(bchanl->bbsmenuwindow, 0, scr);
1369                         bchanl_bbsmenuwindow_scroll(bchanl, 0, scr);
1370                 }
1371                 break;
1372         case KC_CC_R:
1373         case KC_CC_L:
1374                 break;
1375         case KC_PG_U:
1376                 bbsmndraw_getviewrect(draw, &l, &t, &r, &b);
1377                 if (t < (b - t)) {
1378                         scr = -t;
1379                 } else {
1380                         scr = - (b - t);
1381                 }
1382                 bbsmenuwindow_scrollbyvalue(bchanl->bbsmenuwindow, 0, scr);
1383                 bchanl_bbsmenuwindow_scroll(bchanl, 0, scr);
1384                 break;
1385         case KC_PG_D:
1386                 bbsmndraw_getviewrect(draw, &l, &t, &r, &b);
1387                 bbsmnlayout_getdrawrect(layout, &l1, &t1, &r1, &b1);
1388                 if (b + (b - t) > b1) {
1389                         scr = b1 - b;
1390                 } else {
1391                         scr = (b - t);
1392                 }
1393                 if (scr > 0) {
1394                         bbsmenuwindow_scrollbyvalue(bchanl->bbsmenuwindow, 0, scr);
1395                         bchanl_bbsmenuwindow_scroll(bchanl, 0, scr);
1396                 }
1397                 break;
1398         case KC_PG_R:
1399         case KC_PG_L:
1400                 break;
1401         case KC_PF5:
1402                 bchanl_networkrequest_bbsmenu(bchanl);
1403                 break;
1404         case TK_E: /* temporary */
1405                 if (stat & ES_CMD) {
1406                         bchanl_killme(bchanl);
1407                 }
1408                 break;
1409         }
1410 }
1411
1412
1413 LOCAL VOID bchanl_keydwn(bchanl_t *bchanl, UH keytop, TC ch, UW stat)
1414 {
1415         Bool act;
1416
1417         act = subjectwindow_isactive(bchanl->subjectwindow);
1418         if (act == True) {
1419                 bchanl_subjectwindow_keydwn(bchanl, keytop, ch, stat);
1420                 return;
1421         }
1422         act = bbsmenuwindow_isactive(bchanl->bbsmenuwindow);
1423         if (act == True) {
1424                 bchanl_bbsmenuwindow_keydwn(bchanl, keytop, ch, stat);
1425                 return;
1426         }
1427 }
1428
1429 enum BCHANL_TEXTBOX_MENU_TYPE_ {
1430         BCHANL_TEXTBOX_MENU_TYPE_NONE,
1431         BCHANL_TEXTBOX_MENU_TYPE_FILTER,
1432         BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE,
1433         BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL,
1434 };
1435 typedef enum BCHANL_TEXTBOX_MENU_TYPE_ BCHANL_TEXTBOX_MENU_TYPE;
1436
1437 LOCAL VOID bchanl_setupmenu(bchanl_t *bchanl, BCHANL_TEXTBOX_MENU_TYPE type)
1438 {
1439         Bool isopen, isopen_extbbs, selected = False, fromtray, totray, trayempty;
1440         W index, num;
1441
1442         isopen = subjectoptionwindow_isopen(bchanl->subjectoptionwindow);
1443         isopen_extbbs = externalbbswindow_isopen(bchanl->externalbbswindow);
1444         if (isopen_extbbs != False) {
1445                 index = extbbslist_editcontext_getselect(bchanl->bbsmenu.editctx);
1446                 if (index >= 0) {
1447                         selected = True;
1448                 }
1449         }
1450         switch (type) {
1451         case BCHANL_TEXTBOX_MENU_TYPE_NONE:
1452         default:
1453                 fromtray = totray = False;
1454                 break;
1455         case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1456                 trayempty = tray_isempty();
1457                 if (trayempty == False) {
1458                         fromtray = True;
1459                 } else {
1460                         fromtray = False;
1461                 }
1462                 num = subjectoptionwindow_cutfiltertext(bchanl->subjectoptionwindow, NULL, 0, False);
1463                 if (num > 0) {
1464                         totray = True;
1465                 } else {
1466                         totray = False;
1467                 }
1468                 break;
1469         case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1470                 trayempty = tray_isempty();
1471                 if (trayempty == False) {
1472                         fromtray = True;
1473                 } else {
1474                         fromtray = False;
1475                 }
1476                 num = registerexternalwindow_cutboradnametext(bchanl->registerexternalwindow, NULL, 0, False);
1477                 if (num > 0) {
1478                         totray = True;
1479                 } else {
1480                         totray = False;
1481                 }
1482                 break;
1483         case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1484                 trayempty = tray_isempty();
1485                 if (trayempty == False) {
1486                         fromtray = True;
1487                 } else {
1488                         fromtray = False;
1489                 }
1490                 num = registerexternalwindow_cuturltext(bchanl->registerexternalwindow, NULL, 0, False);
1491                 if (num > 0) {
1492                         totray = True;
1493                 } else {
1494                         totray = False;
1495                 }
1496                 break;
1497         }
1498
1499         bchanl_mainmenu_setup(&bchanl->mainmenu, isopen, isopen_extbbs, selected, fromtray, totray);
1500 }
1501
1502 LOCAL VOID bchanl_selectmenu(bchanl_t *bchanl, W sel, BCHANL_TEXTBOX_MENU_TYPE type)
1503 {
1504         Bool isopen;
1505         RECT work;
1506 #define BCHANL_SELECTMENU_STRBUF_LENGTH 256
1507         TC str[BCHANL_SELECTMENU_STRBUF_LENGTH];
1508         W index, len = 0;
1509
1510         switch(sel) {
1511         case BCHANL_MAINMENU_SELECT_CLOSE: /* [½ªÎ»] */
1512                 bchanl_killme(bchanl);
1513                 break;
1514         case BCHANL_MAINMENU_SELECT_REDISPLAY: /* [ºÆɽ¼¨] */
1515                 subjectwindow_requestredisp(bchanl->subjectwindow);
1516                 bbsmenuwindow_requestredisp(bchanl->bbsmenuwindow);
1517                 break;
1518         case BCHANL_MAINMENU_SELECT_BBSMENUFETCH: /* [ÈÄ°ìÍ÷ºÆ¼èÆÀ] */
1519                 bchanl_networkrequest_bbsmenu(bchanl);
1520                 break;
1521         case BCHANL_MAINMENU_SELECT_SUBJECTOPTION: /* [¥¹¥ì°ìÍ÷ÀßÄê] */
1522                 isopen = subjectoptionwindow_isopen(bchanl->subjectoptionwindow);
1523                 if (isopen == False) {
1524                         subjectoptionwindow_open(bchanl->subjectoptionwindow);
1525                 } else {
1526                         subjectoptionwindow_close(bchanl->subjectoptionwindow);
1527                 }
1528                 break;
1529         case BCHANL_MAINMENU_SELECT_EXTBBS_MANAGER: /* [³°ÉôÈĤÎÄɲÃ] */
1530                 isopen = externalbbswindow_isopen(bchanl->externalbbswindow);
1531                 if (isopen == False) {
1532
1533                         bchanl->bbsmenu.editctx = extbbslist_startedit(bchanl->bbsmenu.extbbslist);
1534                         if (bchanl->bbsmenu.editctx == NULL) {
1535                                 break;
1536                         }
1537                         externalbbswindow_open(bchanl->externalbbswindow);
1538                         externalbbswindow_getworkrect(bchanl->externalbbswindow, &work);
1539                         extbbslist_editcontext_setviewrect(bchanl->bbsmenu.editctx, 0, 0, work.c.right - work.c.left, work.c.bottom - work.c.top);
1540                         externalbbswindow_setworkrect(bchanl->externalbbswindow, 0, 0, work.c.right - work.c.left, work.c.bottom - work.c.top);
1541                 }
1542                 break;
1543         case BCHANL_MAINMENU_SELECT_EXTBBS_REGISTER:
1544                 isopen = registerexternalwindow_isopen(bchanl->registerexternalwindow);
1545                 if (isopen == False) {
1546                         registerexternalwindow_open(bchanl->registerexternalwindow);
1547                 }
1548                 break;
1549         case BCHANL_MAINMENU_SELECT_EXTBBS_UP:
1550                 isopen = externalbbswindow_isopen(bchanl->externalbbswindow);
1551                 if (isopen != False) {
1552                         index = extbbslist_editcontext_getselect(bchanl->bbsmenu.editctx);
1553                         if (index < 0) {
1554                                 break;
1555                         }
1556                         extbbslist_editcontext_swapitem(bchanl->bbsmenu.editctx, index-1, index);
1557                         externalbbswindow_requestredisp(bchanl->externalbbswindow);
1558                 }
1559                 break;
1560         case BCHANL_MAINMENU_SELECT_EXTBBS_DOWN:
1561                 isopen = externalbbswindow_isopen(bchanl->externalbbswindow);
1562                 if (isopen != False) {
1563                         index = extbbslist_editcontext_getselect(bchanl->bbsmenu.editctx);
1564                         if (index < 0) {
1565                                 break;
1566                         }
1567                         extbbslist_editcontext_swapitem(bchanl->bbsmenu.editctx, index, index+1);
1568                         externalbbswindow_requestredisp(bchanl->externalbbswindow);
1569                 }
1570                 break;
1571         case BCHANL_MAINMENU_SELECT_EXTBBS_DELETE:
1572                 isopen = externalbbswindow_isopen(bchanl->externalbbswindow);
1573                 if (isopen != False) {
1574                         index = extbbslist_editcontext_getselect(bchanl->bbsmenu.editctx);
1575                         if (index < 0) {
1576                                 break;
1577                         }
1578                         extbbslist_editcontext_deleteitem(bchanl->bbsmenu.editctx, index);
1579                         externalbbswindow_requestredisp(bchanl->externalbbswindow);
1580                 }
1581                 break;
1582         case BCHANL_MAINMENU_SELECT_EDIT_COPY_TO_TRAY:
1583                 switch (type) {
1584                 case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1585                         len = subjectoptionwindow_cutfiltertext(bchanl->subjectoptionwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, False);
1586                         break;
1587                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1588                         len = registerexternalwindow_cutboradnametext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, False);
1589                         break;
1590                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1591                         len = registerexternalwindow_cuturltext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, False);
1592                         break;
1593                 default:
1594                         break;
1595                 }
1596                 if (len > 0) {
1597                         tray_pushstring(str, len);
1598                 }
1599                 break;
1600         case BCHANL_MAINMENU_SELECT_EDIT_COPY_FROM_TRAY:
1601                 len = tray_popstring(str, BCHANL_SELECTMENU_STRBUF_LENGTH);
1602                 switch (type) {
1603                 case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1604                         subjectoptionwindow_insertfiltertext(bchanl->subjectoptionwindow, str, len);
1605                         break;
1606                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1607                         registerexternalwindow_insertboradnametext(bchanl->registerexternalwindow, str, len);
1608                         break;
1609                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1610                         registerexternalwindow_inserturltext(bchanl->registerexternalwindow, str, len);
1611                         break;
1612                 default:
1613                         break;
1614                 }
1615                 break;
1616         case BCHANL_MAINMENU_SELECT_EDIT_MOVE_TO_TRAY:
1617                 switch (type) {
1618                 case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1619                         len = subjectoptionwindow_cutfiltertext(bchanl->subjectoptionwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1620                         break;
1621                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1622                         len = registerexternalwindow_cutboradnametext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1623                         break;
1624                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1625                         len = registerexternalwindow_cuturltext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1626                         break;
1627                 default:
1628                         break;
1629                 }
1630                 if (len > 0) {
1631                         tray_pushstring(str, len);
1632                 }
1633                 break;
1634         case BCHANL_MAINMENU_SELECT_EDIT_MOVE_FROM_TRAY:
1635                 len = tray_popstring(str, BCHANL_SELECTMENU_STRBUF_LENGTH);
1636                 switch (type) {
1637                 case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1638                         subjectoptionwindow_insertfiltertext(bchanl->subjectoptionwindow, str, len);
1639                         break;
1640                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1641                         registerexternalwindow_insertboradnametext(bchanl->registerexternalwindow, str, len);
1642                         break;
1643                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1644                         registerexternalwindow_inserturltext(bchanl->registerexternalwindow, str, len);
1645                         break;
1646                 default:
1647                         break;
1648                 }
1649                 tray_deletedata();
1650                 break;
1651         case BCHANL_MAINMENU_SELECT_EDIT_DELETE:
1652                 switch (type) {
1653                 case BCHANL_TEXTBOX_MENU_TYPE_FILTER:
1654                         subjectoptionwindow_cutfiltertext(bchanl->subjectoptionwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1655                         break;
1656                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE:
1657                         registerexternalwindow_cutboradnametext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1658                         break;
1659                 case BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL:
1660                         registerexternalwindow_cuturltext(bchanl->registerexternalwindow, str, BCHANL_SELECTMENU_STRBUF_LENGTH, True);
1661                         break;
1662                 default:
1663                         break;
1664                 }
1665                 break;
1666         }
1667         return;
1668 }
1669
1670 LOCAL VOID bchanl_popupmenu(bchanl_t *bchanl, PNT pos, BCHANL_TEXTBOX_MENU_TYPE type)
1671 {
1672         W sel;
1673         bchanl_setupmenu(bchanl, type);
1674         gset_ptr(PS_SELECT, NULL, -1, -1);
1675         sel = bchanl_mainmenu_popup(&bchanl->mainmenu, pos);
1676         if (sel > 0) {
1677                 bchanl_selectmenu(bchanl, sel, type);
1678         }
1679 }
1680
1681 LOCAL W bchanl_keyselect(bchanl_t *bchanl, TC keycode, BCHANL_TEXTBOX_MENU_TYPE type)
1682 {
1683         W sel;
1684         bchanl_setupmenu(bchanl, type);
1685         sel = bchanl_mainmenu_keyselect(&bchanl->mainmenu, keycode);
1686         if (sel > 0) {
1687                 bchanl_selectmenu(bchanl, sel, type);
1688         }
1689         return 0;
1690 }
1691
1692 LOCAL VOID bchanl_handletimeout(bchanl_t *bchanl, W code)
1693 {
1694         switch (code) {
1695         case BCHANL_MESSAGE_RETRIEVER_RELAYOUT:
1696                 bchanl_bbsmenu_relayout(&bchanl->bbsmenu, bchanl->bbsmenuwindow);
1697                 bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_SELECT);
1698                 pdsp_msg(NULL);
1699                 break;
1700         case BCHANL_MESSAGE_RETRIEVER_ERROR:
1701                 bchanl_hmistate_updateptrstyle(&bchanl->hmistate, PS_SELECT);
1702                 pdsp_msg(NULL);
1703                 break;
1704         }
1705 }
1706
1707 LOCAL VOID bchanl_eventdispatch(bchanl_t *bchanl)
1708 {
1709         bchanlhmievent_t *evt;
1710         W sel, err;
1711         Bool close;
1712
1713         err = bchanlhmi_getevent(bchanl->hmi, &evt);
1714         if (err < 0) {
1715                 return;
1716         }
1717
1718         switch (evt->type) {
1719         case BCHANLHMIEVENT_TYPE_COMMON_MOUSEMOVE:
1720                 break;
1721         case BCHANLHMIEVENT_TYPE_COMMON_KEYDOWN:
1722                 if (evt->data.common_keydown.stat & ES_CMD) {   /*Ì¿Îᥭ¡¼*/
1723                         bchanl_setupmenu(bchanl, BCHANL_TEXTBOX_MENU_TYPE_NONE);
1724                         sel = bchanl_keyselect(bchanl, evt->data.common_keydown.keycode, BCHANL_TEXTBOX_MENU_TYPE_NONE);
1725                         if (sel > 0) {
1726                                 bchanl_selectmenu(bchanl, sel, BCHANL_TEXTBOX_MENU_TYPE_NONE);
1727                                 break;
1728                         }
1729                 }
1730                 bchanl_keydwn(bchanl, evt->data.common_keydown.keytop, evt->data.common_keydown.keycode, evt->data.common_keydown.stat);
1731                 break;
1732         case BCHANLHMIEVENT_TYPE_COMMON_MENU:
1733                 bchanl_popupmenu(bchanl, evt->data.common_menu.pos, BCHANL_TEXTBOX_MENU_TYPE_NONE);
1734                 break;
1735         case BCHANLHMIEVENT_TYPE_COMMON_TIMEOUT:
1736                 bchanl_handletimeout(bchanl, evt->data.common_timeout.code);
1737                 break;
1738         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_DRAW:
1739                 bchanl_subjectwindow_draw(bchanl);
1740                 break;
1741         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_RESIZE:
1742                 bchanl_subjectwindow_resize(bchanl, evt->data.subjectwindow_resize.work_sz);
1743                 break;
1744         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_CLOSE:
1745                 bchanl_subjectwindow_close(bchanl);
1746                 break;
1747         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_BUTDN:
1748                 bchanl_subjectwindow_butdn(bchanl, evt->data.subjectwindow_butdn.type, evt->data.subjectwindow_butdn.pos);
1749                 break;
1750         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_PASTE:
1751                 subjectwindow_responsepasterequest(bchanl->subjectwindow, /* NACK */ 1, NULL);
1752                 break;
1753         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_MOUSEMOVE:
1754                 gset_ptr(bchanl->hmistate.ptr, NULL, -1, -1);
1755                 break;
1756         case BCHANLHMIEVENT_TYPE_SUBJECTWINDOW_SCROLL:
1757                 bchanl_subjectwindow_scroll(bchanl, evt->data.subjectwindow_scroll.dh, evt->data.subjectwindow_scroll.dv);
1758                 break;
1759         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_DRAW:
1760                 bchanl_bbsmenuwindow_draw(bchanl);
1761                 break;
1762         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_RESIZE:
1763                 bchanl_bbsmenuwindow_resize(bchanl, evt->data.bbsmenuwindow_resize.work_sz);
1764                 break;
1765         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_CLOSE:
1766                 bchanl_bbsmenuwindow_close(bchanl);
1767                 break;
1768         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_BUTDN:
1769                 bchanl_bbsmenuwindow_butdn(bchanl, evt->data.bbsmenuwindow_butdn.type, evt->data.bbsmenuwindow_butdn.pos);
1770                 break;
1771         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_MOUSEMOVE:
1772                 gset_ptr(bchanl->hmistate.ptr, NULL, -1, -1);
1773                 break;
1774         case BCHANLHMIEVENT_TYPE_BBSMENUWINDOW_SCROLL:
1775                 bchanl_bbsmenuwindow_scroll(bchanl, evt->data.bbsmenuwindow_scroll.dh, evt->data.bbsmenuwindow_scroll.dv);
1776                 break;
1777         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_FILTER_DETERMINE:
1778                 bchanl_changesubjectfilterword(bchanl, evt->data.subjectoptionwindow_filter_determine.value, evt->data.subjectoptionwindow_filter_determine.len);
1779                 break;
1780         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_FILTER_COPY:
1781                 break;
1782         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_FILTER_MOVE:
1783                 break;
1784         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_FILTER_MENU:
1785                 bchanl_popupmenu(bchanl, evt->data.subjectoptionwindow_filter_menu.pos, BCHANL_TEXTBOX_MENU_TYPE_FILTER);
1786                 break;
1787         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_FILTER_KEYMENU:
1788                 bchanl_keyselect(bchanl, evt->data.subjectoptionwindow_filter_keymenu.keycode, BCHANL_TEXTBOX_MENU_TYPE_FILTER);
1789                 break;
1790         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_ORDER_CHANGE:
1791                 bchanl_changesubjectorder(bchanl, evt->data.subjectoptionwindow_order_change.value);
1792                 break;
1793         case BCHANLHMIEVENT_TYPE_SUBJECTOPTIONWINDOW_PARTS_ORDERBY_CHANGE:
1794                 bchanl_changesubjectorderby(bchanl, evt->data.subjectoptionwindow_order_change.value);
1795                 break;
1796         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_BORADNAME_DETERMINE:
1797                 break;
1798         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_BORADNAME_COPY:
1799                 break;
1800         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_BORADNAME_MOVE:
1801                 break;
1802         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_BORADNAME_MENU:
1803                 bchanl_popupmenu(bchanl, evt->data.registerexternalwindow_boradname_menu.pos, BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE);
1804                 break;
1805         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_BORADNAME_KEYMENU:
1806                 bchanl_keyselect(bchanl, evt->data.registerexternalwindow_boradname_keymenu.keycode, BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_TITLE);
1807                 break;
1808         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_URL_DETERMINE:
1809                 break;
1810         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_URL_COPY:
1811                 break;
1812         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_URL_MOVE:
1813                 break;
1814         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_URL_MENU:
1815                 bchanl_popupmenu(bchanl, evt->data.registerexternalwindow_url_menu.pos, BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL);
1816                 break;
1817         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_URL_KEYMENU:
1818                 bchanl_keyselect(bchanl, evt->data.registerexternalwindow_url_keymenu.keycode, BCHANL_TEXTBOX_MENU_TYPE_EXTBBS_URL);
1819                 break;
1820         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_DETERMINE_PUSH:
1821                 close = bchanl_registerexternalbbs(bchanl);
1822                 if (close != False) {
1823                         registerexternalwindow_close(bchanl->registerexternalwindow);
1824                 }
1825                 break;
1826         case BCHANLHMIEVENT_TYPE_REGISTEREXTERNALWINDOW_PARTS_CANCEL_PUSH:
1827                 registerexternalwindow_close(bchanl->registerexternalwindow);
1828                 break;
1829         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_DRAW:
1830                 bchanl_externalbbswindow_draw(bchanl);
1831                 break;
1832         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_RESIZE:
1833                 break;
1834                 bchanl_externalbbswindow_resize(bchanl, evt->data.externalbbswindow_resize.work_sz);
1835         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_CLOSE:
1836                 bchanl_externalbbswindow_close(bchanl);
1837                 break;
1838         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_BUTDN:
1839                 bchanl_externalbbswindow_butdn(bchanl, evt->data.externalbbswindow_butdn.type, evt->data.externalbbswindow_butdn.pos);
1840                 break;
1841         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_PASTE:
1842                 bchanl_externalbbswindow_paste(bchanl);
1843                 break;
1844         case BCHANLHMIEVENT_TYPE_EXTERNALBBSWINDOW_SCROLL:
1845                 bchanl_externalbbswindow_scroll(bchanl, evt->data.externalbbswindow_scroll.dh, evt->data.externalbbswindow_scroll.dv);
1846                 break;
1847         case BCHANLHMIEVENT_TYPE_NONE:
1848         }
1849 }
1850
1851 LOCAL TC filename_dbg_databox[] = (TC[]){TK_b, TK_c, TK_h, TK_a, TK_n, TK_l, TK_PROD, TK_d, TK_b, TK_x, TNULL};
1852 LOCAL TC filename_dbg_storage[] = (TC[]){TK_c, TK_o, TK_m, TK_m, TK_o, TK_n, TK_s, TK_t, TK_o, TK_r, TK_a, TK_g, TK_e, TK_2, TNULL};
1853 LOCAL TC filename_storage[] = (TC[]){TK_c, TK_o, TK_m, TK_m, TK_o, TK_n, TK_s, TK_t, TK_o, TK_r, TK_a, TK_g, TK_e, TNULL};
1854
1855 LOCAL W main_CLI_args(VID *vid, LINK *storage)
1856 {
1857         W err;
1858         LINK dbx;
1859
1860         *vid = -1;
1861         err = get_lnk(filename_dbg_databox, &dbx, F_NORM);
1862         if (err < 0) {
1863                 DP_ER("get_lnk:test databox error", err);
1864                 return err;
1865         }
1866         err = dopn_dat(&dbx);
1867         if (err < 0) {
1868                 DP_ER("dopn_dat error", err);
1869                 return err;
1870         }
1871         err = get_lnk(filename_dbg_storage, storage, F_NORM);
1872         if (err < 0) {
1873                 DP_ER("get_lnk;commonstorage error", err);
1874                 return err;
1875         }
1876
1877         return 0;
1878 }
1879
1880 LOCAL W main_EXECREC_args(M_EXECREQ *msg, VID *vid, LINK *storage)
1881 {
1882         W err;
1883         LINK lnk;
1884
1885         err = dopn_dat(&msg->self);
1886         if (err < 0) {
1887                 DP_ER("dopn_dat", err);
1888                 return err;
1889         }
1890
1891         lnk = msg->self;
1892         err = get_lnk(filename_storage, &lnk, F_BASED);
1893         if (err < 0) {
1894                 DP_ER("get_lnk;commonstorage error", err);
1895                 return err;
1896         }
1897         *storage = lnk;
1898
1899         *vid = msg->vid;
1900
1901         return 0;
1902 }
1903
1904 typedef struct _arg {
1905         W ac;
1906         TC **argv;
1907 } CLI_arg;
1908
1909 LOCAL    CLI_arg   MESSAGEtoargv(const MESSAGE *src)
1910 {
1911         W len,i,ac;
1912         TC *str;
1913         TC **argv;
1914         CLI_arg ret;
1915
1916         len = src->msg_size / sizeof(TC);
1917         str = (TC*)(src->msg_body.ANYMSG.msg_str);
1918         ac = 0;
1919         for(i=0;i<len;i++){
1920                 if(str[i] == TK_KSP){
1921                         str[i] = TNULL;
1922                         continue;
1923                 }
1924                 ac++;
1925                 for(;i<len;i++){
1926                         if(str[i] == TK_KSP){
1927                                 i--;
1928                                 break;
1929                         }
1930                 }
1931         }
1932
1933         argv = (TC**)malloc(sizeof(TC*)*ac);
1934
1935         ac = 0;
1936         for(i=0;i<len;i++){
1937                 if(str[i] == TNULL){
1938                         str[i] = TNULL;
1939                         continue;
1940                 }
1941                 argv[ac++] = str+i;
1942                 for(;i<len;i++){
1943                         if(str[i] == TNULL){
1944                                 i--;
1945                                 break;
1946                         }
1947                 }
1948         }
1949
1950         ret.ac = ac;
1951         ret.argv = argv;
1952
1953         return ret;
1954 }
1955
1956 EXPORT  W       MAIN(MESSAGE *msg)
1957 {
1958         W err;
1959         VID vid = -1;
1960         LINK storage;
1961         CLI_arg arg;
1962         bchanl_t bchanl;
1963
1964         err = dopn_dat(NULL);
1965         if (err < 0) {
1966                 DP_ER("dopn_dat error:", err);
1967                 ext_prc(0);
1968         }
1969
1970         switch (msg->msg_type) {
1971         case 0: /* CLI */
1972                 arg = MESSAGEtoargv(msg);
1973                 err = main_CLI_args(&vid, &storage);
1974                 if (err < 0) {
1975                         ext_prc(0);
1976                 }
1977                 break;
1978         case DISPREQ:
1979                 oend_req(((M_DISPREQ*)msg)->vid, -1);
1980                 ext_prc(0);
1981                 break;
1982         case PASTEREQ:
1983                 oend_req(((M_PASTEREQ*)msg)->vid, -1);
1984                 ext_prc(0);
1985                 break;
1986         case EXECREQ:
1987                 if ((((M_EXECREQ*)msg)->mode & 2) == 0) {
1988                         ext_prc(0);
1989                 }
1990                 err = main_EXECREC_args((M_EXECREQ*)msg, &vid, &storage);
1991                 if (err < 0) {
1992                         ext_prc(0);
1993                 }
1994                 break;
1995         default:
1996                 ext_prc(0);
1997                 break;
1998         }
1999
2000         err = bchanl_initialize(&bchanl, vid, msg->msg_type, &storage);
2001         if (err < 0) {
2002                 DP_ER("bchanl_initialize error", err);
2003                 ext_prc(0);
2004         }
2005         err = bchanl_prepare_network(&bchanl);
2006         if (err < 0) {
2007                 DP_ER("bchanl_prepare_network error", err);
2008                 bchanl_killme(&bchanl);
2009                 return err;
2010         }
2011
2012         if (msg->msg_type == 0) {
2013                 bchanl_readbbsmenutestdata(&(bchanl.bbsmenu), bchanl.bbsmenuwindow);
2014         } else if (msg->msg_type == EXECREQ) {
2015                 bchanl_networkrequest_bbsmenu(&bchanl);
2016         }
2017
2018         subjectwindow_requestredisp(bchanl.subjectwindow);
2019         bbsmenuwindow_requestredisp(bchanl.bbsmenuwindow);
2020
2021         for (;;) {
2022                 bchanl_eventdispatch(&bchanl);
2023         }
2024
2025         return 0;
2026 }