OSDN Git Service

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