OSDN Git Service

fdeb504c4fc4aecd6c7eb146b42bfd0f88f8bf90
[ntch/develop.git] / src / main.c
1 /* Copyright 2013 Akira Ohta (akohta001@gmail.com)
2     This file is part of ntch.
3
4     The ntch is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8
9     The ntch is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with ntch.  If not, see <http://www.gnu.org/licenses/>.
16     
17 */
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <locale.h>
25 #include <iconv.h>
26 #include <netinet/in.h>
27 #include <assert.h>
28
29 #include "env.h"
30 #include "error.h"
31 #include "nt_string.h"
32 #include "utils/nt_std_t.h"
33 #include "net/nt_http.h"
34 #include "net/nt_socket.h"
35 #include "net/nt_cookie.h"
36 #include "utils/file.h"
37 #include "usr/usr_db_t.h"
38 #include "utils/nt_mutex.h"
39 #include "utils/nt_pthread.h"
40 #include "utils/nt_timer.h"
41 #include "utils/base64.h"
42 #include "utils/crypt.h"
43 #include "usr/favorite_t.h"
44 #include "_2ch/_2ch.h"
45 #include "_2ch/maru_2ch.h"
46 #include "_2ch/search_2ch.h"
47 #include "ui/disp.h"
48 #include "ui/disp_win.h"
49 #include "ui/disp_string.h"
50 #ifdef NT_CLOUD
51 #include "cloud/nt_cloud.h"
52 #endif
53 #define S_SIZE  (1024)
54
55 static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr);
56 #ifdef NT_CLOUD
57 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
58                         nt_cloud_handle h_cloud,
59                         nt_favorite_handle h_favorite, 
60                         nt_favorite_grp_handle h_favorite_grp);
61 #else
62 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
63                         nt_favorite_handle h_favorite, 
64                         nt_favorite_grp_handle h_favorite_grp);
65 #endif
66 static void print_error(WINDOW *wp, const wchar_t *msg);
67
68 static void _2ch_selected_item_free(void *ptr)
69 {
70         nt_2ch_selected_item_release_ref(
71                 (nt_2ch_selected_item_handle)ptr);
72
73 }
74
75 int main(int argc, char *argv[])
76 {
77         int result = 1;
78         WINDOW *scrp;
79         nt_usr_db_handle usr_db_handle;
80         nt_favorite_handle h_favorite;
81         nt_favorite_grp_handle h_favorite_grp;
82         nt_link_tp text_linkp, text2_linkp;
83         const char *err_msg;
84 #ifdef NT_CLOUD
85         nt_cloud_handle h_cloud;
86         h_cloud = NULL;
87 #endif
88         err_msg = NULL;
89
90         setlocale(LC_ALL, "ja_JP.UTF-8");
91         
92         if(0 != set_option(argc, argv)){
93                 return 1;
94         }
95
96         sleep(1);
97
98
99         usr_db_handle = nt_usr_db_init_lib(USR_LOG_DB_PATH);
100         if(!usr_db_handle){
101                 fputs("Couldn't initialize usr database.\n", stderr);
102                 printf("Exit.");
103                 return 1;
104         }
105
106         scrp = initscr();
107         if(!scrp){
108                 fputs("Couldn't initialize Curses libraly.\n", stderr);
109                 printf("Exit.");
110                 return 1;
111         }
112
113         nt_timer_lib_init();
114         
115         nt_mutex_lib_init();
116         
117         if(!nt_pthread_lib_init(
118                         NT_PTHREAD_POOL_SIZE, 
119                         NT_PTHREAD_POOL_QUEUE_SIZE, 
120                         &err_msg)){
121                 if(err_msg)
122                         fputs(err_msg, stderr);
123                 goto ERROR_TRAP;
124         }
125         
126 #ifdef NT_CLOUD
127         if(nt_crypt_lib_init(RFC2898_SALT, RFC2898_ITERATION, 
128                         AES256_PASS, &err_msg)){
129                 if(NCE_AUTH_URL && NCE_ID && NCE_PASS){
130                         h_cloud = nt_cloud_init(NCE_AUTH_URL, NCE_ID, NCE_PASS);
131                 }
132         }else{
133                 if(err_msg){
134                         fputs(err_msg, stderr);
135                         sleep(1);
136                 }
137         }
138 #endif
139
140         if(!nt_2ch_model_init()){
141                 fputs("Failed to read board menu data.\n", stderr);
142                 goto ERROR_TRAP;
143         }
144
145         if(!nt_init_board_menu()){
146                 fputs("Failed to initialize board menu data.\n", stderr);
147                 goto ERROR_TRAP;
148         }
149         
150
151         h_favorite = nt_favorite_alloc(L"favorite");
152         if(!h_favorite){
153                 goto ERROR_TRAP;
154         }
155         h_favorite_grp = nt_favorite_grp_alloc(h_favorite, 
156                                 L"お気に入りのスレッド",
157                                 NT_FAVORITE_GRP_FLAG_FOLDER_OPEN);
158         if(!h_favorite_grp){
159                 nt_favorite_release_ref(h_favorite);
160                 goto ERROR_TRAP;
161         }
162         
163         text_linkp = NULL;
164 #ifdef NT_CLOUD
165         if(h_cloud){
166                 text_linkp = nt_cloud_download_file(h_cloud, "fb.txt");
167         }
168 #endif
169         if(!text_linkp)
170                 text_linkp = nt_read_text_file(USR_FAVORITE_BOARD_FILE_PATH);
171         if(text_linkp){
172                 nt_favorite_load_boards(h_favorite, text_linkp);
173                 nt_all_link_free(text_linkp, free);
174         }
175         text_linkp = NULL;
176 #ifdef NT_CLOUD
177         if(h_cloud){
178                 text_linkp = nt_cloud_download_file(h_cloud, "ft.txt");
179         }
180 #endif
181         if(!text_linkp)
182                 text_linkp = nt_read_text_file(USR_FAVORITE_THREAD_FILE_PATH);
183         if(text_linkp){
184                 nt_favorite_load_threads(h_favorite, h_favorite_grp, text_linkp);
185                 nt_all_link_free(text_linkp, free);
186         }
187         
188         cbreak();
189         noecho();
190
191 #ifdef NT_CLOUD
192         if(DoLoop(scrp, usr_db_handle, h_cloud, h_favorite, h_favorite_grp))
193 #else
194         if(DoLoop(scrp, usr_db_handle, h_favorite, h_favorite_grp))
195 #endif
196                 result = 0;
197
198         echo();
199         nocbreak();
200         
201         text_linkp = nt_favorite_retrieve_boards(h_favorite);
202         if(text_linkp){
203                 nt_write_text_file(USR_FAVORITE_BOARD_FILE_PATH, text_linkp);
204                 nt_all_link_free(text_linkp, free);
205         }else{
206                 unlink(USR_FAVORITE_BOARD_FILE_PATH);
207         }
208         if(nt_favorite_retrieve_threads(h_favorite, 
209                         &text_linkp, &text2_linkp)){
210                 if(text_linkp)
211                         nt_all_link_free(text_linkp, free);
212                 if(text2_linkp){
213                         nt_write_text_file(USR_FAVORITE_THREAD_FILE_PATH, text2_linkp);
214                         nt_all_link_free(text2_linkp, free);
215                 }else{
216                         unlink(USR_FAVORITE_THREAD_FILE_PATH);
217                 }
218         }
219
220         nt_favorite_grp_release_ref(h_favorite_grp);
221         nt_favorite_release_ref(h_favorite);
222
223 ERROR_TRAP:
224         clear();
225
226
227         nt_2ch_model_release_ref(app_2ch_model);
228
229         endwin();
230
231         nt_usr_db_finish_lib(usr_db_handle);
232         
233         nt_pthread_lib_finish();
234         
235         nt_mutex_lib_finish();
236
237         nt_timer_lib_finish();
238         
239 #ifdef NT_CLOUD
240         nt_crypt_lib_finish();
241         if(h_cloud)
242                 nt_cloud_release_ref(h_cloud);
243 #endif
244         nt_env_free();
245         return (result);
246 }
247
248 #define TIMER_ID_AUTO_UPDATE_NONE 0
249 #define TIMER_ID_AUTO_UPDATE 1
250 #define TIMER_ID_AUTO_SCROLL 2
251 static int auto_update_timer_func(int id)
252 {
253         switch(id){
254         case TIMER_ID_AUTO_UPDATE:
255                 return TIMER_ID_AUTO_UPDATE;
256         case TIMER_ID_AUTO_SCROLL:
257                 return TIMER_ID_AUTO_SCROLL;
258         }
259         return TIMER_ID_AUTO_UPDATE_NONE;
260 }
261
262 #ifdef NT_CLOUD
263 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
264                 nt_cloud_handle h_cloud,
265                 nt_favorite_handle h_favorite, 
266                 nt_favorite_grp_handle h_favorite_grp)
267 #else
268 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
269                 nt_favorite_handle h_favorite, 
270                 nt_favorite_grp_handle h_favorite_grp)
271 #endif
272 {
273         int ch, state, num;
274         int disp_state, nresult;
275         nt_window_tp bwinp = NULL;
276         nt_window_tp twinp = NULL;
277         nt_window_tp rwinp = NULL;
278         nt_window_tp search_winp = NULL;
279         nt_window_tp favorite_winp = NULL;
280         char buf[256];
281         wchar_t title_buf[128];
282         wchar_t wch;
283         const wchar_t *title, *board_name;
284         const wchar_t *status_msg;
285         BOOL result = FALSE;
286         nt_write_data_handle h_write_data;
287         nt_maru_2ch_tp marup;
288         nt_cookie_tp cookiep;
289         char *search;
290         nt_searched_thread_handle h_searched_thread;
291         nt_2ch_selected_item_handle h_sel_items;
292         nt_2ch_selected_item_handle h_sel_items_tmp;
293         nt_favorite_board_handle h_favorite_board;
294         nt_favorite_thread_handle h_favorite_thread;
295         void *handle;
296         nt_pthread_result_t async_data;
297         nt_link_tp linkp, linkp2;
298         BOOL auto_scrolling;
299         nt_timer_handle h_timer_auto_update;
300         nt_timer_handle h_timer_auto_scroll;
301         nt_timer_handle h_timer;
302         
303         state = DISP_STATE_BOARDMENU;
304         if(INIT_DISP_STATE == NT_INTI_DISP_FAVORITE){
305                 disp_state = DISP_STATE_FAVORITE; 
306         }else{
307                 disp_state = DISP_STATE_BOARDMENU; 
308         }
309         cookiep = nt_load_cookies(USR_COOKIE_PATH);
310
311         if(MARU_ID && MARU_PW) 
312                 marup = nt_maru_2ch_alloc(MARU_ID, MARU_PW);
313         h_timer_auto_scroll = nt_timer_alloc(
314                         TIMER_ID_AUTO_SCROLL, -1, auto_update_timer_func);
315         h_timer_auto_update = nt_timer_alloc(
316                         TIMER_ID_AUTO_UPDATE, NT_AUTO_UPDATE_INTERVAL, auto_update_timer_func);
317
318         h_write_data = NULL;
319         marup = NULL;
320         status_msg = NULL;
321         h_searched_thread = NULL;
322         h_sel_items_tmp = NULL;
323         h_sel_items = nt_2ch_selected_item_alloc();
324         if(!h_sel_items)
325                 return FALSE;
326
327         ch = NT_KEY_NONE;
328         bwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
329         if(!bwinp)
330                 return FALSE;
331         twinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
332         if(!twinp)
333                 return FALSE;
334         rwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
335         if(!rwinp)
336                 return FALSE;
337         
338         
339         keypad(stdscr, true);
340         while(1){
341                 if(FORCE_REFRESH)
342                         wclear(scrp);
343                 else
344                         werase(scrp);
345                         
346                 
347                 switch(disp_state){
348                 case DISP_STATE_BOARDMENU:
349                         werase(bwinp->wp);
350                         bwinp->key = ch;
351                         draw_title(scrp, L"板一覧", WA_REVERSE);
352                         if(!nt_disp_win_move(scrp, bwinp, LINES-1, COLS, 1, 0))
353                                 goto END_WHILE;
354                         state = disp_board_menu(bwinp, app_2ch_model, h_sel_items);
355                         if(DISP_CMD(state)){
356                                 if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
357                                         board_name = nt_2ch_selected_item_get_board_name(h_sel_items);
358                                         h_favorite_board = nt_favorite_board_alloc(
359                                                 h_favorite, board_name);
360                                         if(h_favorite_board){
361 #ifdef NT_CLOUD
362                                                 linkp = nt_link_add_data(NULL, (void*)board_name);
363                                                 if(linkp){
364                                                         if(h_cloud)
365                                                                 nt_cloud_insert_lines_into_file(h_cloud, "fb.txt", linkp);
366                                                         free(linkp);
367                                                 }
368 #endif
369                                                 nt_favorite_board_release_ref(h_favorite_board);
370                                                 //favorite_dump(h_favorite);
371                                         }
372                                 }
373                                 state = DISP_STATE_BOARDMENU;
374                                 ch = NT_KEY_NONE;
375                         }
376                         if(DISP_STATE_ERROR == state){
377                                 goto END_WHILE;
378                         }else if(DISP_STATE_THREADTITLE == state){
379                                 if(nt_read_board(h_sel_items)){
380                                         disp_state = state;
381                                         state = DISP_STATE_BOARDMENU;
382                                         if(twinp->data){
383                                                 free_threadlist_ctx(twinp->data);
384                                                 twinp->data = NULL;
385                                         }
386                                         ch = NT_KEY_NONE;
387                                         continue;
388                                 }else{
389                                         print_error(scrp, NT_ERR_MSG_COUDLNOT_READ_BOARD);
390                                 }
391                         }else if(state == DISP_STATE_SEARCH_THREAD){
392                                 state = DISP_STATE_BOARDMENU;
393                                 disp_state = DISP_STATE_SEARCH_THREAD;
394                                 ch = NT_KEY_NONE;
395                                 continue;
396                         }else if(DISP_STATE_FAVORITE == state){
397                                 state = DISP_STATE_BOARDMENU;
398                                 disp_state = DISP_STATE_FAVORITE;
399                                 ch = NT_KEY_NONE;
400                                 continue;
401                         }
402                         break;
403                 case DISP_STATE_THREADTITLE:
404                         werase(twinp->wp);
405                         twinp->key = ch;
406                         twinp->status_msg = NULL;
407                         title = nt_2ch_selected_item_get_board_name(h_sel_items);
408                         draw_title(scrp, title, WA_REVERSE);
409                         if(!nt_disp_win_move(scrp, twinp, LINES-1, COLS, 1, 0))
410                                 goto END_WHILE;
411                         state = disp_threadlist(twinp, state, h_sel_items, db_handle);
412                         if(DISP_CMD(state)){
413                                 if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
414                                         h_favorite_thread = nt_favorite_thread_alloc(
415                                                 h_favorite_grp,
416                                                 nt_2ch_selected_item_get_thread_dat_name(h_sel_items),
417                                                 nt_2ch_selected_item_get_board_name(h_sel_items),
418                                                 nt_2ch_selected_item_get_thread_title(h_sel_items));
419                                         if(h_favorite_thread){
420 #ifdef NT_CLOUD
421                                                 linkp = NULL;
422                                                 if(nt_favorite_retrieve_thread(h_favorite_thread, &linkp)){
423                                                         if(h_cloud)
424                                                                 nt_cloud_insert_lines_into_file(h_cloud, "ft.txt", linkp);
425                                                         nt_all_link_free(linkp, free);
426                                                 }
427 #endif
428                                                 nt_favorite_thread_release_ref(h_favorite_thread);
429                                                 //favorite_dump(h_favorite);
430                                                 status_msg = NT_INFO_ADD_FAVORITE_SUCCEEDED;
431                                         }else{
432                                                 status_msg = NT_ERR_MSG_ADD_FAVORITE_FAILED;
433                                         }
434                                 }
435                                 state = DISP_STATE_THREADTITLE;
436                                 ch = NT_KEY_NONE;
437                         }else if(DISP_STATE_ERROR == state){
438                                 goto END_WHILE;
439                         }else if(DISP_STATE_BOARDMENU == state){
440                                         disp_state = state;
441                                         ch = NT_KEY_NONE;
442                                         continue;
443                         }else if(DISP_STATE_REFRESH == state){
444                                 if(nt_read_board(h_sel_items)){
445                                         if(twinp->data){
446                                                 free_threadlist_ctx(twinp->data);
447                                                 twinp->data = NULL;
448                                         }
449                                         ch = NT_KEY_NONE;
450                                         status_msg = NT_INFO_REFRESH_BOARD_SUCCESS;
451                                         state = DISP_STATE_THREADTITLE;
452                                         disp_state = state;
453                                         continue;
454                                 }else{
455                                         status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD;
456                                 }
457                                 state = DISP_STATE_THREADTITLE;
458                         }else if(DISP_STATE_RESLIST == state){
459                                 disp_state = state;
460                                 if(!nt_read_thread(h_sel_items)){
461                                         if(!rwinp->data){
462                                                 state = DISP_STATE_THREADTITLE;
463                                                 disp_state = state;
464                                         }
465                                         wclear(scrp);
466                                         ch = NT_KEY_NONE;
467                                         continue;
468                                 }
469                                 if(twinp->data){
470                                         init_threadlist_ctx(twinp->data);
471                                 }
472                                 if(rwinp->data){
473                                         free_reslist_ctx(rwinp->data);
474                                         rwinp->data = NULL;
475                                 }
476                                 state = DISP_STATE_THREADTITLE;
477                                 ch = NT_KEY_NONE;
478                                 continue;
479                         }else if(DISP_STATE_SEARCH_THREAD == state){
480                                 state = DISP_STATE_THREADTITLE;
481                                 disp_state = DISP_STATE_SEARCH_THREAD;
482                                 ch = NT_KEY_NONE;
483                                 continue;
484                         }else if(DISP_STATE_FAVORITE == state){
485                                 state = DISP_STATE_THREADTITLE;
486                                 disp_state = DISP_STATE_FAVORITE;
487                                 ch = NT_KEY_NONE;
488                                 continue;
489                         }else{
490                                 status_msg = twinp->status_msg;
491                         }
492                         break;
493                 case DISP_STATE_RESLIST:
494                         werase(rwinp->wp);
495                         title = nt_2ch_selected_item_get_thread_title(h_sel_items);
496                         if(!title){
497                                 num = draw_title(scrp, L"Title not found.", WA_REVERSE);
498                         }else if(-1 == swprintf(title_buf, sizeof(title_buf)/sizeof(wchar_t),
499                                         L"[%ls] - %ls", 
500                                         nt_2ch_selected_item_get_board_name(h_sel_items),
501                                         title)){
502                                 num = draw_title(scrp, title, WA_REVERSE);
503                         }else{
504                                 num = draw_title(scrp, title_buf, WA_REVERSE);
505                         }
506                         if(!nt_disp_win_move(scrp, rwinp, 
507                                                 LINES - num, COLS, num, 0))
508                                 goto END_WHILE;
509                         rwinp->key = ch;
510                         state = disp_reslist(rwinp, state, h_sel_items, db_handle);
511                         auto_scrolling = FALSE;
512                         if(DISP_CMD(state)){
513                                 if(DISP_CMD(state) == DISP_CMD_AUTO_SCROLL){
514                                         if(0 >= nt_timer_get_interval(h_timer_auto_scroll)){
515                                                 nt_timer_set_interval(
516                                                         h_timer_auto_scroll, NT_AUTO_SCROLL_INTERVAL);
517                                         }
518                                         auto_scrolling = TRUE;
519                                 }
520                                 DISP_CLR_CMD(state);
521                         }
522                         if(!auto_scrolling){
523                                 nt_timer_set_interval(h_timer_auto_scroll, -1);
524                         }
525                         if(DISP_STATE_ERROR == state){
526                                 goto END_WHILE;
527                         }else if(state == DISP_STATE_REFRESH){
528                                 state = DISP_STATE_RESLIST;
529                                 ch = NT_KEY_NONE;
530                                 if(!nt_read_thread(h_sel_items)){
531                                         status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED;
532                                         wclear(scrp);
533                                         continue;
534                                 }
535                                 if(rwinp->data){
536                                         free_reslist_ctx(rwinp->data);
537                                         rwinp->data = NULL;
538                                 }
539                                 status_msg = NT_INFO_REFRESH_THREAD_SUCCESS;
540                                 wclear(scrp);
541                                 continue;
542                         }else if(state == DISP_STATE_SEARCH_THREAD){
543                                 state = DISP_STATE_RESLIST;
544                                 disp_state = DISP_STATE_SEARCH_THREAD;
545                                 ch = NT_KEY_NONE;
546                                 continue;
547                         }else if(DISP_STATE_FAVORITE == state){
548                                 state = DISP_STATE_RESLIST;
549                                 disp_state = DISP_STATE_FAVORITE;
550                                 ch = NT_KEY_NONE;
551                                 continue;
552                         }else if(state != DISP_STATE_RESLIST){
553                                 disp_state = state;
554                                 ch = NT_KEY_NONE;
555                                 continue;
556                         }
557                         break;
558                 case DISP_STATE_EDITOR:
559                         disp_state = DISP_STATE_RESLIST;
560                         state = DISP_STATE_RESLIST;
561                         ch = NT_KEY_NONE;
562                         if(h_write_data)
563                                 nt_write_data_release_ref(h_write_data);
564                         h_write_data = nt_write_data_alloc();
565                         if(!h_write_data)
566                                 goto END_WHILE;
567                         if(disp_editor(h_write_data)){
568                                 if(marup && !marup->sid)
569                                         get_session_id(marup);
570                                 if(nt_write_msg(h_sel_items, 
571                                                 h_write_data, cookiep, marup)){
572                                         disp_state = DISP_STATE_HTML_RESULT;
573                                         continue;
574                                 }
575                         }
576                         keypad(stdscr, true);
577                         status_msg = nt_write_data_get_status_msg(h_write_data);
578                         wclear(scrp);
579                         continue;
580                 case DISP_STATE_HTML_RESULT:
581                         nresult = disp_html_result(h_write_data);
582                         if(0 == nresult){
583                                 if(!nt_read_thread(h_sel_items))
584                                         break;
585                                 if(rwinp->data){
586                                         free_reslist_ctx(rwinp->data);
587                                         rwinp->data = NULL;
588                                 }
589                         }else if(1 == nresult){
590                                 if(nt_write_msg(h_sel_items, 
591                                                 h_write_data, cookiep, marup)){
592                                         if(0 == disp_html_result(h_write_data)){
593                                                 if(!nt_read_thread(h_sel_items))
594                                                         break;
595                                                 if(rwinp->data){
596                                                         free_reslist_ctx(rwinp->data);
597                                                         rwinp->data = NULL;
598                                                 }
599                                         }
600                                 }
601                         }
602                         keypad(stdscr, true);
603                         disp_state = DISP_STATE_RESLIST;
604                         state = DISP_STATE_RESLIST;
605                         ch = NT_KEY_NONE;
606                         status_msg = nt_write_data_get_status_msg(h_write_data);
607                         wclear(scrp);
608                         continue;
609                 case DISP_STATE_SEARCH_THREAD:
610                         draw_title(scrp, L"全板検索", WA_REVERSE);
611                         if(!search_winp)
612                                 search_winp = nt_disp_win_alloc(
613                                                 scrp, LINES-1, COLS, 1, 0, buf);
614                         if(!search_winp)
615                                 goto END_WHILE;
616                         search_winp->key = ch;
617                         linkp = NULL;
618                         if(nt_get_search_text(buf, &search)){
619                                 if(search){
620                                         linkp = nt_search_all_board(
621                                                         app_2ch_model, search, &status_msg);
622                                         free(search);
623                                         buf[0] = '\0';
624                                 }
625                         }
626                         h_searched_thread = NULL;
627                         disp_state = disp_thread_search(search_winp, 
628                                         state, linkp, &h_searched_thread);
629                         ch = NT_KEY_NONE;
630                         if(h_searched_thread){
631                                 if(nt_set_sel_item(app_2ch_model,
632                                                 &h_sel_items_tmp, h_searched_thread, &status_msg)){
633                                         disp_state = DISP_STATE_RESLIST;
634                                         nt_2ch_selected_item_release_ref(h_sel_items);
635                                         h_sel_items = h_sel_items_tmp;
636                                         if(rwinp->data){
637                                                 free_reslist_ctx(rwinp->data);
638                                                 rwinp->data = NULL;
639                                         }
640                                         if(twinp->data){
641                                                 free_threadlist_ctx(twinp->data);
642                                                 twinp->data = NULL;
643                                         }
644                                         nt_searched_thread_release_ref(h_searched_thread);
645                                         h_searched_thread = NULL;
646                                         continue;
647                                 }
648                                 nt_searched_thread_release_ref(h_searched_thread);
649                                 h_searched_thread = NULL;
650                         }
651                         if(disp_state != DISP_STATE_SEARCH_THREAD){
652                                 continue;
653                         }
654                         break;
655                 case DISP_STATE_FAVORITE:
656                         draw_title(scrp, L"お気に入り", WA_REVERSE);
657                         if(!favorite_winp)
658                                 favorite_winp = nt_disp_win_alloc(
659                                                 scrp, LINES-1, COLS, 1, 0, buf);
660                         if(!favorite_winp)
661                                 goto END_WHILE;
662                         favorite_winp->key = ch;
663                         h_searched_thread = NULL;
664                         if(!favorite_winp->data){
665                                 linkp = nt_favorite_get_update_board_list(app_2ch_model, h_favorite);
666                                 if(linkp){
667                                         nt_read_board_list(linkp);
668                                         nt_all_link_free(linkp, _2ch_selected_item_free);
669                                 }
670                         }
671                         state = disp_favorite(favorite_winp, state, app_2ch_model,
672                                                         h_favorite, db_handle, 
673                                                         &handle,  &h_searched_thread);
674                         if(DISP_CMD(state)){
675                                 ch = NT_KEY_NONE;
676                                 if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_BOARD){
677                                         if(nt_favorite_board_remove(handle)){
678                                                 h_favorite_board = (nt_favorite_board_handle)handle;
679 #ifdef NT_CLOUD
680                                                 if(h_cloud){
681                                                         linkp = nt_link_add_data(NULL, 
682                                                                         (void*)nt_favorite_board_get_name(h_favorite_board));
683                                                         if(linkp){
684                                                                 nt_cloud_delete_lines_from_file(h_cloud, "fb.txt", linkp);
685                                                                 free(linkp);
686                                                         }
687                                                 }
688 #endif
689                                                 nt_favorite_board_release_ref(h_favorite_board);
690                                                 status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
691                                         }else{
692                                                 status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
693                                         }
694                                 }else if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_THREAD){
695                                         if(nt_favorite_thread_remove(handle)){
696                                                 h_favorite_thread = (nt_favorite_thread_handle)handle;
697 #ifdef NT_CLOUD
698                                                 if(h_cloud){
699                                                         linkp = NULL;
700                                                         if(nt_favorite_retrieve_thread(h_favorite_thread, &linkp)){
701                                                                 nt_cloud_delete_lines_from_file(h_cloud, "ft.txt", linkp);
702                                                                 nt_all_link_free(linkp, free);
703                                                         }
704                                                 }
705 #endif
706                                                 nt_favorite_thread_release_ref(h_favorite_thread);
707                                                 status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
708                                         }else{
709                                                 status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
710                                         }
711                                 }else if(DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD ||
712                                                 DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_THREAD){
713                                         assert(h_searched_thread);
714                                         if(nt_set_sel_item(app_2ch_model,
715                                                         &h_sel_items_tmp, h_searched_thread, &status_msg)){
716                                                 disp_state = (DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD)
717                                                         ? DISP_STATE_THREADTITLE : DISP_STATE_RESLIST;
718                                                 state = DISP_STATE_FAVORITE;
719                                                 nt_2ch_selected_item_release_ref(h_sel_items);
720                                                 h_sel_items = h_sel_items_tmp;
721                                                 if(rwinp->data){
722                                                         free_reslist_ctx(rwinp->data);
723                                                         rwinp->data = NULL;
724                                                 }
725                                                 if(twinp->data){
726                                                         free_threadlist_ctx(twinp->data);
727                                                         twinp->data = NULL;
728                                                 }
729                                         }
730                                         nt_searched_thread_release_ref(h_searched_thread);
731                                         h_searched_thread = NULL;
732 #ifdef NT_CLOUD
733                                 }else if(h_cloud){
734                                         if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
735                                                         DISP_CMD(state) == DISP_CMD_UPLOAD_BOARDS){
736                                                 status_msg = NT_ERR_MSG_UPLOAD_FAVORITE_FAILED;
737                                                 linkp = nt_favorite_retrieve_boards(h_favorite);
738                                                 if(linkp){
739                                                         if(nt_cloud_upload_file(h_cloud, "fb.txt", linkp)){
740                                                                 status_msg = NT_INFO_UPLOAD_FAVORITE_SUCCEEDED;
741                                                         }
742                                                         nt_all_link_free(linkp, free);
743                                                 }
744                                         }
745                                         if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
746                                                         DISP_CMD(state) == DISP_CMD_UPLOAD_THREADS){
747                                                 if(nt_favorite_retrieve_threads(h_favorite, 
748                                                                 &linkp, &linkp2)){
749                                                         if(linkp)
750                                                                 nt_all_link_free(linkp, free);
751                                                         if(linkp2){
752                                                                 if(nt_cloud_upload_file(h_cloud, "ft.txt", linkp2)){
753                                                                         status_msg = NT_INFO_UPLOAD_FAVORITE_SUCCEEDED;
754                                                                 }
755                                                                 nt_all_link_free(linkp2, free);
756                                                         }
757                                                 }
758                                         }
759                                         disp_state = state = DISP_STATE_FAVORITE;
760 #endif
761                                 }else{
762                                         disp_state = state = DISP_STATE_FAVORITE;
763                                 }
764                                 continue;
765                         }else if(state == DISP_STATE_REFRESH){
766                                 state = DISP_STATE_FAVORITE;
767                                 ch = NT_KEY_NONE;
768                                 if(favorite_winp->data){
769                                         free_favorite_ctx(favorite_winp->data);
770                                         favorite_winp->data = NULL;
771                                 }
772                                 status_msg = NT_INFO_REFRESH_FAVORITE_SUCCESS;
773                                 wclear(scrp);
774                                 continue;
775                         }else if(state != DISP_STATE_FAVORITE){
776                                 ch = NT_KEY_NONE;
777                                 disp_state = state;
778                                 continue;
779                         }else{
780                                 disp_state = DISP_STATE_FAVORITE;
781                         }
782                         break;
783                 default:
784                         goto END_WHILE;
785                 }/* end switch*/
786
787                 if(status_msg){
788                         print_error(scrp, status_msg);
789                         status_msg = NULL;
790                 }
791
792                 move(LINES-1,COLS-1);
793                 touchwin(scrp);
794                 wrefresh(scrp);
795                 
796                 timeout(NT_MAINLOOP_POLLING_INTERVAL);
797                 do{
798                         ch = getch();
799                         if(ch == ERR){
800                                 async_data = nt_pthread_get_result_from_que();
801                                 if(async_data.code == NT_PTHREAD_RESULT_UPDATE_BOARD){
802                                         ch = NT_KEY_CMD_BOARD_UPDATE;
803                                         //fprintf(stderr, "Async result recieved.!\n");
804                                 }else{
805                                         h_timer = nt_timer_ring_a_bell();
806                                         if(h_timer){
807                                                 switch(nt_timer_get_id(h_timer)){
808                                                 case TIMER_ID_AUTO_SCROLL:
809                                                         ch = NT_KEY_CMD_AUTO_SCROLL;
810                                                         break;
811                                                 case TIMER_ID_AUTO_UPDATE:
812                                                         linkp = nt_favorite_get_update_board_list(
813                                                                         app_2ch_model, h_favorite);
814                                                         if(linkp){
815                                                                 nt_read_board_list(linkp);
816                                                                 nt_all_link_free(linkp, _2ch_selected_item_free);
817                                                                 //fprintf(stderr, "Update request calling.!\n");
818                                                         }
819                                                         break;
820                                                 }
821                                                 nt_timer_release_ref(h_timer);
822                                         }
823                                 }
824                         }
825                 }while(ch == '\n' || ch == '\r' || ch == ERR);
826                 timeout(-1);
827                 
828                 switch(ch){
829                 case NT_KEY_UP:
830                 case KEY_UP:
831                 case NT_KEY_DOWN:
832                 case KEY_DOWN:
833                 case NT_KEY_LEFT:
834                 case NT_KEY_RIGHT:
835                 case KEY_RIGHT:
836                 case NT_KEY_PAGEUP:
837                 case KEY_PPAGE:
838                 case NT_KEY_PAGEDOWN:
839                 case KEY_NPAGE:
840                 case NT_KEY_SELECT:
841                 case NT_KEY_ADD:
842                 case NT_KEY_DEL:
843                 case NT_KEY_BOTTOM:
844                 case KEY_END:
845                 case NT_KEY_REFRESH:
846                         break;
847                 case NT_KEY_CLOSE:
848                 case KEY_LEFT:
849                         wclear(scrp);
850                         break;
851                 case KEY_HOME:
852                         ch = NT_KEY_COMMAND1;
853                         nt_add_wch(scrp,ch,0);
854                         strncpy(buf,"1",2);
855                         break;
856                 case NT_KEY_COMMAND1:
857                 case NT_KEY_COMMAND2:
858                 case NT_KEY_COMMAND3:
859                         echo();
860                         nocbreak();
861                         wch = ch;
862                         move(LINES-1,0);
863                         nt_add_wch(scrp,wch,0);
864                         getstr(buf);
865                         cbreak();
866                         noecho();
867                         break;
868                 case NT_KEY_ERASE:
869                         wclear(scrp);
870                         break;
871                 case NT_KEY_QUIT:
872                         result = TRUE;
873                         goto END_WHILE;
874                 }/* end switch*/
875         }/* end while */
876 END_WHILE:
877         if(h_timer_auto_update)
878                 nt_timer_release_ref(h_timer_auto_update);
879         if(h_timer_auto_scroll)
880                 nt_timer_release_ref(h_timer_auto_scroll);
881         if(cookiep)
882                 nt_unload_cookie(cookiep);
883         if(marup)
884                 nt_maru_2ch_free(marup);
885         if(h_write_data)
886                 nt_write_data_release_ref(h_write_data);
887         if(h_searched_thread)
888                 nt_searched_thread_release_ref(h_searched_thread);
889         nt_2ch_selected_item_release_ref(h_sel_items);
890         free_board_menu_ctx(bwinp->data);
891         free_threadlist_ctx(twinp->data);
892         free_reslist_ctx(rwinp->data);
893         if(search_winp){
894                 if(search_winp->data)
895                         free_search_thread_ctx(search_winp->data);
896                 nt_disp_win_free(search_winp);
897         }
898         if(favorite_winp){
899                 if(favorite_winp->data)
900                         free_favorite_ctx(favorite_winp->data);
901                 nt_disp_win_free(favorite_winp);
902         }
903         nt_disp_win_free(bwinp);
904         nt_disp_win_free(twinp);
905         nt_disp_win_free(rwinp);
906         
907         return result;
908 }
909
910
911
912 static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr)
913 {
914         move(0,0);
915         int  num;
916         num = nt_get_wc_count_within_colmns(title, COLS-1);
917         if(num == 0)
918                 return 0;
919         
920         nt_add_wnch(wp, L' ', attr, COLS);
921         move(0,1);
922         nt_add_wnstr(wp, title, WA_REVERSE, COLS - 1);
923         return 1;
924 }
925
926
927
928 static void print_error(WINDOW *wp, const wchar_t *msg)
929 {
930         move(LINES-1,0);
931         nt_add_wstr(wp, msg, 0);
932 }
933