OSDN Git Service

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