OSDN Git Service

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