OSDN Git Service

v1.0.2.6
[ntch/develop.git] / src / main.c
1 /* Copyright 2013,2014 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 #include "cloud/nt_cloud.h"
51 #include "usr/ng_word_t.h"
52
53 #define S_SIZE  (1024)
54
55 extern int server_main();
56
57 static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr);
58 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
59                         nt_cloud_handle h_cloud,
60                         nt_favorite_handle h_favorite, 
61                         nt_favorite_grp_handle h_favorite_grp,
62                         nt_ng_word_handle h_ng_word);
63 static void print_error(WINDOW *wp, const wchar_t *msg);
64
65 static void _2ch_selected_item_free(void *ptr)
66 {
67         nt_2ch_selected_item_release_ref(
68                 (nt_2ch_selected_item_handle)ptr);
69
70 }
71
72 int main(int argc, char *argv[])
73 {
74         int result = 1;
75         WINDOW *scrp;
76         nt_usr_db_handle usr_db_handle;
77         nt_favorite_handle h_favorite;
78         nt_favorite_grp_handle h_favorite_grp;
79         nt_link_tp text_linkp, text2_linkp;
80         const char *err_msg;
81         nt_ng_word_handle h_ng_word;
82         nt_cloud_handle h_cloud;
83         h_cloud = NULL;
84         err_msg = NULL;
85
86         setlocale(LC_ALL, "ja_JP.UTF-8");
87         
88         if(0 != set_option(argc, argv)){
89                 return 1;
90         }
91         
92         if(APP_MODE == NT_APP_MODE_SERVER){
93                 return server_main();
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         if(nt_crypt_lib_init(RFC2898_SALT, RFC2898_ITERATION, 
127                         AES256_PASS, &err_msg)){
128                 if(NCE_AUTH_URL && NCE_ID && NCE_PASS){
129                         h_cloud = nt_cloud_init(NCE_AUTH_URL, NCE_ID, NCE_PASS);
130                 }
131         }else{
132                 if(err_msg){
133                         fputs(err_msg, stderr);
134                         sleep(1);
135                 }
136         }
137
138         if(!nt_2ch_model_init()){
139                 fputs("Failed to read board menu data.\n", stderr);
140                 goto ERROR_TRAP;
141         }
142
143         if(!nt_init_board_menu()){
144                 fputs("Failed to initialize board menu data.\n", stderr);
145                 goto ERROR_TRAP;
146         }
147         
148
149         h_favorite = nt_favorite_alloc(L"favorite");
150         if(!h_favorite){
151                 goto ERROR_TRAP;
152         }
153         h_favorite_grp = nt_favorite_grp_alloc(h_favorite, 
154                                 L"お気に入りのスレッド",
155                                 NT_FAVORITE_GRP_FLAG_FOLDER_OPEN);
156         if(!h_favorite_grp){
157                 nt_favorite_release_ref(h_favorite);
158                 goto ERROR_TRAP;
159         }
160         
161         text_linkp = NULL;
162         if(h_cloud){
163                 text_linkp = nt_cloud_download_file(h_cloud, "fb.txt");
164         }
165         if(!text_linkp)
166                 text_linkp = nt_read_text_file(USR_FAVORITE_BOARD_FILE_PATH);
167         if(text_linkp){
168                 nt_favorite_load_boards(h_favorite, text_linkp);
169                 nt_all_link_free(text_linkp, free);
170         }
171         text_linkp = NULL;
172         if(h_cloud){
173                 text_linkp = nt_cloud_download_file(h_cloud, "ft.txt");
174                 nt_cloud_query_favorite_attributes_async(h_cloud, usr_db_handle);
175                 //nt_cloud_query_attributes(h_cloud, usr_db_handle, 0);
176         }
177         if(!text_linkp)
178                 text_linkp = nt_read_text_file(USR_FAVORITE_THREAD_FILE_PATH);
179         if(text_linkp){
180                 nt_favorite_load_threads(h_favorite, h_favorite_grp, text_linkp);
181                 nt_all_link_free(text_linkp, free);
182         }
183         
184         h_ng_word = nt_ng_word_load(h_cloud,
185                         USR_NG_WORD_FILE_PATH,
186                         USR_NG_NAME_FILE_PATH,
187                         USR_NG_ID_FILE_PATH);
188         
189         cbreak();
190         noecho();
191
192         if(DoLoop(scrp, usr_db_handle, h_cloud, h_favorite, h_favorite_grp, h_ng_word))
193                 result = 0;
194
195         echo();
196         nocbreak();
197         
198         if(h_ng_word){
199                 nt_ng_word_save(h_ng_word,
200                         USR_NG_WORD_FILE_PATH,
201                         USR_NG_NAME_FILE_PATH,
202                         USR_NG_ID_FILE_PATH);
203                 nt_ng_word_release_ref(h_ng_word);
204         }
205         
206         text_linkp = nt_favorite_retrieve_boards(h_favorite);
207         if(text_linkp){
208                 nt_write_text_file(USR_FAVORITE_BOARD_FILE_PATH, text_linkp);
209                 nt_all_link_free(text_linkp, free);
210         }else{
211                 unlink(USR_FAVORITE_BOARD_FILE_PATH);
212         }
213         if(nt_favorite_retrieve_threads(h_favorite, 
214                         &text_linkp, &text2_linkp)){
215                 if(text_linkp)
216                         nt_all_link_free(text_linkp, free);
217                 if(text2_linkp){
218                         nt_write_text_file(USR_FAVORITE_THREAD_FILE_PATH, text2_linkp);
219                         nt_all_link_free(text2_linkp, free);
220                 }else{
221                         unlink(USR_FAVORITE_THREAD_FILE_PATH);
222                 }
223         }
224
225         nt_favorite_grp_release_ref(h_favorite_grp);
226         nt_favorite_release_ref(h_favorite);
227
228 ERROR_TRAP:
229         clear();
230
231
232         nt_2ch_model_release_ref(app_2ch_model);
233
234         endwin();
235
236         nt_usr_db_finish_lib(usr_db_handle);
237         
238         nt_pthread_lib_finish();
239         
240         nt_mutex_lib_finish();
241
242         nt_timer_lib_finish();
243         
244         nt_crypt_lib_finish();
245         if(h_cloud)
246                 nt_cloud_release_ref(h_cloud);
247         nt_env_free();
248         return (result);
249 }
250
251 #define TIMER_ID_AUTO_UPDATE_NONE 0
252 #define TIMER_ID_AUTO_UPDATE 1
253 #define TIMER_ID_AUTO_SCROLL 2
254 static int auto_update_timer_func(int id)
255 {
256         switch(id){
257         case TIMER_ID_AUTO_UPDATE:
258                 return TIMER_ID_AUTO_UPDATE;
259         case TIMER_ID_AUTO_SCROLL:
260                 return TIMER_ID_AUTO_SCROLL;
261         }
262         return TIMER_ID_AUTO_UPDATE_NONE;
263 }
264
265 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
266                 nt_cloud_handle h_cloud,
267                 nt_favorite_handle h_favorite, 
268                 nt_favorite_grp_handle h_favorite_grp,
269                 nt_ng_word_handle h_ng_word)
270 {
271         int ch, state, num;
272         int disp_state, nresult;
273         nt_window_tp bwinp = NULL;
274         nt_window_tp twinp = NULL;
275         nt_window_tp rwinp = NULL;
276         nt_window_tp search_winp = NULL;
277         nt_window_tp favorite_winp = NULL;
278         nt_window_tp history_winp = NULL;
279         char buf[256];
280         wchar_t title_buf[128];
281         wchar_t wch;
282         const wchar_t *title, *board_name;
283         const wchar_t *status_msg;
284         BOOL result = FALSE;
285         nt_write_data_handle h_write_data;
286         nt_maru_2ch_tp marup;
287         nt_cookie_tp cookiep;
288         char *search;
289         nt_searched_thread_handle h_searched_thread;
290         nt_2ch_selected_item_handle h_sel_items;
291         nt_2ch_selected_item_handle h_sel_items_tmp;
292         nt_favorite_board_handle h_favorite_board;
293         nt_favorite_thread_handle h_favorite_thread;
294         void *handle;
295         nt_pthread_result_t async_data;
296         nt_link_tp linkp, linkp2;
297         BOOL auto_scrolling;
298         nt_timer_handle h_timer_auto_update;
299         nt_timer_handle h_timer_auto_scroll;
300         nt_timer_handle h_timer;
301         
302         state = DISP_STATE_BOARDMENU;
303         if(INIT_DISP_STATE == NT_INTI_DISP_FAVORITE){
304                 disp_state = DISP_STATE_FAVORITE; 
305         }else if(INIT_DISP_STATE == NT_INTI_DISP_HISTORY){
306                 disp_state = DISP_STATE_HISTORY; 
307         }else{
308                 disp_state = DISP_STATE_BOARDMENU; 
309         }
310         cookiep = nt_load_cookies(USR_COOKIE_PATH);
311
312         if(MARU_ID && MARU_PW) 
313                 marup = nt_maru_2ch_alloc(MARU_ID, MARU_PW);
314         h_timer_auto_scroll = nt_timer_alloc(
315                         TIMER_ID_AUTO_SCROLL, -1, auto_update_timer_func);
316         h_timer_auto_update = nt_timer_alloc(
317                         TIMER_ID_AUTO_UPDATE, NT_AUTO_UPDATE_INTERVAL, auto_update_timer_func);
318
319         h_write_data = NULL;
320         marup = NULL;
321         status_msg = NULL;
322         h_searched_thread = NULL;
323         h_sel_items_tmp = NULL;
324         h_sel_items = nt_2ch_selected_item_alloc();
325         if(!h_sel_items)
326                 return FALSE;
327
328         ch = NT_KEY_NONE;
329         bwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
330         if(!bwinp)
331                 return FALSE;
332         twinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
333         if(!twinp)
334                 return FALSE;
335         rwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
336         if(!rwinp)
337                 return FALSE;
338         
339         
340         keypad(stdscr, true);
341         while(1){
342                 if(FORCE_REFRESH)
343                         wclear(scrp);
344                 else
345                         werase(scrp);
346                         
347                 
348                 switch(disp_state){
349                 case DISP_STATE_BOARDMENU:
350                         werase(bwinp->wp);
351                         bwinp->key = ch;
352                         draw_title(scrp, L"板一覧", WA_REVERSE);
353                         if(!nt_disp_win_move(scrp, bwinp, LINES-1, COLS, 1, 0))
354                                 goto END_WHILE;
355                         state = disp_board_menu(bwinp, app_2ch_model, h_sel_items);
356                         if(DISP_CMD(state)){
357                                 if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
358                                         board_name = nt_2ch_selected_item_get_board_name(h_sel_items);
359                                         h_favorite_board = nt_favorite_board_alloc(
360                                                 h_favorite, board_name);
361                                         if(h_favorite_board){
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                                                 nt_favorite_board_release_ref(h_favorite_board);
369                                                 //favorite_dump(h_favorite);
370                                         }
371                                 }
372                                 state = DISP_STATE_BOARDMENU;
373                                 ch = NT_KEY_NONE;
374                         }
375                         if(DISP_STATE_ERROR == state){
376                                 goto END_WHILE;
377                         }else if(DISP_STATE_THREADTITLE == state){
378                                 if(nt_read_board(h_sel_items)){
379                                         disp_state = state;
380                                         state = DISP_STATE_BOARDMENU;
381                                         if(twinp->data){
382                                                 free_threadlist_ctx(twinp->data);
383                                                 twinp->data = NULL;
384                                         }
385                                         ch = NT_KEY_NONE;
386                                         continue;
387                                 }else{
388                                         print_error(scrp, NT_ERR_MSG_COUDLNOT_READ_BOARD);
389                                 }
390                         }else if(state != DISP_STATE_BOARDMENU){
391                                 disp_state = state;
392                                 state = DISP_STATE_BOARDMENU;
393                                 ch = NT_KEY_NONE;
394                                 continue;
395                         }
396                         break;
397                 case DISP_STATE_THREADTITLE:
398                         werase(twinp->wp);
399                         twinp->key = ch;
400                         twinp->status_msg = NULL;
401                         title = nt_2ch_selected_item_get_board_name(h_sel_items);
402                         draw_title(scrp, title, WA_REVERSE);
403                         if(!nt_disp_win_move(scrp, twinp, LINES-1, COLS, 1, 0))
404                                 goto END_WHILE;
405                         state = disp_threadlist(twinp, state, h_sel_items, db_handle);
406                         if(DISP_CMD(state)){
407                                 if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
408                                         h_favorite_thread = nt_favorite_thread_alloc(
409                                                 h_favorite_grp,
410                                                 nt_2ch_selected_item_get_thread_dat_name(h_sel_items),
411                                                 nt_2ch_selected_item_get_board_name(h_sel_items),
412                                                 nt_2ch_selected_item_get_thread_title(h_sel_items));
413                                         if(h_favorite_thread){
414                                                 linkp = NULL;
415                                                 if(nt_favorite_retrieve_thread(h_favorite_thread, &linkp)){
416                                                         if(h_cloud)
417                                                                 nt_cloud_insert_lines_into_file(h_cloud, "ft.txt", linkp);
418                                                         nt_all_link_free(linkp, free);
419                                                 }
420                                                 nt_favorite_thread_release_ref(h_favorite_thread);
421                                                 //favorite_dump(h_favorite);
422                                                 status_msg = NT_INFO_ADD_FAVORITE_SUCCEEDED;
423                                         }else{
424                                                 status_msg = NT_ERR_MSG_ADD_FAVORITE_FAILED;
425                                         }
426                                 }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
427                                         if(nt_read_board(h_sel_items)){
428                                                 if(twinp->data){
429                                                         free_threadlist_ctx(twinp->data);
430                                                         twinp->data = NULL;
431                                                 }
432                                                 ch = NT_KEY_NONE;
433                                                 status_msg = NT_INFO_REFRESH_BOARD_SUCCESS;
434                                                 state = DISP_STATE_THREADTITLE;
435                                                 disp_state = state;
436                                                 continue;
437                                         }else{
438                                                 status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD;
439                                         }
440                                 }
441                                 state = DISP_STATE_THREADTITLE;
442                                 ch = NT_KEY_NONE;
443                         }else if(DISP_STATE_ERROR == state){
444                                 goto END_WHILE;
445                         }else if(DISP_STATE_BOARDMENU == state){
446                                         disp_state = state;
447                                         ch = NT_KEY_NONE;
448                                         continue;
449                         }else if(DISP_STATE_RESLIST == state){
450                                 disp_state = state;
451                                 if(!nt_read_thread(h_sel_items)){
452                                         if(!rwinp->data){
453                                                 state = DISP_STATE_THREADTITLE;
454                                                 disp_state = state;
455                                         }
456                                         wclear(scrp);
457                                         ch = NT_KEY_NONE;
458                                         continue;
459                                 }
460                                 if(twinp->data){
461                                         init_threadlist_ctx(twinp->data);
462                                 }
463                                 if(rwinp->data){
464                                         free_reslist_ctx(rwinp->data);
465                                         rwinp->data = NULL;
466                                 }
467                                 state = DISP_STATE_THREADTITLE;
468                                 ch = NT_KEY_NONE;
469                                 continue;
470                         }else if(DISP_STATE_THREADTITLE != state){
471                                 disp_state = state;
472                                 state = DISP_STATE_THREADTITLE;
473                                 ch = NT_KEY_NONE;
474                                 continue;
475                         }else{
476                                 status_msg = twinp->status_msg;
477                         }
478                         break;
479                 case DISP_STATE_RESLIST:
480                         werase(rwinp->wp);
481                         title = nt_2ch_selected_item_get_thread_title(h_sel_items);
482                         if(!title){
483                                 num = draw_title(scrp, L"Title not found.", WA_REVERSE);
484                         }else if(-1 == swprintf(title_buf, sizeof(title_buf)/sizeof(wchar_t),
485                                         L"[%ls] - %ls", 
486                                         nt_2ch_selected_item_get_board_name(h_sel_items),
487                                         title)){
488                                 num = draw_title(scrp, title, WA_REVERSE);
489                         }else{
490                                 num = draw_title(scrp, title_buf, WA_REVERSE);
491                         }
492                         if(!nt_disp_win_move(scrp, rwinp, 
493                                                 LINES - num, COLS, num, 0))
494                                 goto END_WHILE;
495                         rwinp->key = ch;
496                         state = disp_reslist(rwinp, state, h_sel_items, db_handle, h_ng_word, h_cloud);
497                         auto_scrolling = FALSE;
498                         if(DISP_CMD(state)){
499                                 if(DISP_CMD(state) == DISP_CMD_AUTO_SCROLL){
500                                         if(0 >= nt_timer_get_interval(h_timer_auto_scroll)){
501                                                 nt_timer_set_interval(
502                                                         h_timer_auto_scroll, NT_AUTO_SCROLL_INTERVAL);
503                                         }
504                                         auto_scrolling = TRUE;
505                                         state = DISP_STATE_RESLIST;
506                                 }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
507                                         state = DISP_STATE_RESLIST;
508                                         ch = NT_KEY_NONE;
509                                         if(!nt_read_thread(h_sel_items)){
510                                                 status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED;
511                                                 wclear(scrp);
512                                                 continue;
513                                         }
514                                         if(rwinp->data){
515                                                 free_reslist_ctx(rwinp->data);
516                                                 rwinp->data = NULL;
517                                         }
518                                         status_msg = NT_INFO_REFRESH_THREAD_SUCCESS;
519                                         wclear(scrp);
520                                         continue;
521                                 }else if(DISP_CMD(state) == DISP_CMD_REENTER){
522                                         DISP_CLR_CMD(state);
523                                         ch = NT_KEY_NONE;
524                                         continue;
525                                 }else if(DISP_CMD(state) == DISP_CMD_EDIT_NGWORD){
526                                         ch = NT_KEY_NONE;
527                                         if(!h_ng_word)
528                                                 break;
529                                         linkp = nt_ng_word_get_words(h_ng_word);
530                                         linkp = disp_editor3(linkp);
531                                         if(linkp && nt_ng_word_set_words(h_ng_word, linkp, h_cloud)){
532                                                 ch = NT_KEY_CMD_NGWORD_UPDATE;
533                                         }
534                                         DISP_CLR_CMD(state);
535                                         keypad(stdscr, true);
536                                         wclear(scrp);
537                                         continue;
538                                 }else if(DISP_CMD(state) == DISP_CMD_EDIT_NGNAME){
539                                         ch = NT_KEY_NONE;
540                                         if(!h_ng_word)
541                                                 break;
542                                         linkp = nt_ng_word_get_names(h_ng_word);
543                                         linkp = disp_editor3(linkp);
544                                         if(linkp && nt_ng_word_set_names(h_ng_word, linkp, h_cloud)){
545                                                 ch = NT_KEY_CMD_NGWORD_UPDATE;
546                                         }
547                                         DISP_CLR_CMD(state);
548                                         keypad(stdscr, true);
549                                         wclear(scrp);
550                                         continue;
551                                 }else if(DISP_CMD(state) == DISP_CMD_EDIT_NGID){
552                                         ch = NT_KEY_NONE;
553                                         if(!h_ng_word)
554                                                 break;
555                                         linkp = nt_ng_word_get_ids(h_ng_word);
556                                         linkp = disp_editor3(linkp);
557                                         if(linkp && nt_ng_word_set_ids(h_ng_word, linkp, h_cloud)){
558                                                 ch = NT_KEY_CMD_NGWORD_UPDATE;
559                                         }
560                                         DISP_CLR_CMD(state);
561                                         keypad(stdscr, true);
562                                         wclear(scrp);
563                                         continue;
564                                 }
565                         }
566                         if(!auto_scrolling){
567                                 nt_timer_set_interval(h_timer_auto_scroll, -1);
568                         }
569                         if(DISP_STATE_ERROR == state){
570                                 goto END_WHILE;
571                         }else if(state != DISP_STATE_RESLIST){
572                                 disp_state = state;
573                                 state = DISP_STATE_RESLIST;
574                                 ch = NT_KEY_NONE;
575                                 continue;
576                         }
577                         break;
578                 case DISP_STATE_EDITOR:
579                         disp_state = DISP_STATE_RESLIST;
580                         state = DISP_STATE_RESLIST;
581                         ch = NT_KEY_NONE;
582                         if(h_write_data)
583                                 nt_write_data_release_ref(h_write_data);
584                         h_write_data = nt_write_data_alloc();
585                         if(!h_write_data)
586                                 goto END_WHILE;
587                         if(disp_editor(h_write_data)){
588                                 if(marup && !marup->sid)
589                                         get_session_id(marup);
590                                 if(nt_write_msg(h_sel_items, 
591                                                 h_write_data, cookiep, marup)){
592                                         disp_state = DISP_STATE_HTML_RESULT;
593                                         continue;
594                                 }
595                         }
596                         keypad(stdscr, true);
597                         status_msg = nt_write_data_get_status_msg(h_write_data);
598                         wclear(scrp);
599                         continue;
600                 case DISP_STATE_HTML_RESULT:
601                         nresult = disp_html_result(h_write_data);
602                         if(0 == nresult){
603                                 if(!nt_read_thread(h_sel_items))
604                                         break;
605                                 if(rwinp->data){
606                                         free_reslist_ctx(rwinp->data);
607                                         rwinp->data = NULL;
608                                 }
609                         }else if(1 == nresult){
610                                 if(nt_write_msg(h_sel_items, 
611                                                 h_write_data, cookiep, marup)){
612                                         if(0 == disp_html_result(h_write_data)){
613                                                 if(!nt_read_thread(h_sel_items))
614                                                         break;
615                                                 if(rwinp->data){
616                                                         free_reslist_ctx(rwinp->data);
617                                                         rwinp->data = NULL;
618                                                 }
619                                         }
620                                 }
621                         }
622                         keypad(stdscr, true);
623                         disp_state = DISP_STATE_RESLIST;
624                         state = DISP_STATE_RESLIST;
625                         ch = NT_KEY_NONE;
626                         status_msg = nt_write_data_get_status_msg(h_write_data);
627                         wclear(scrp);
628                         continue;
629                 case DISP_STATE_SEARCH_THREAD:
630                         draw_title(scrp, L"全板検索", WA_REVERSE);
631                         if(!search_winp)
632                                 search_winp = nt_disp_win_alloc(
633                                                 scrp, LINES-1, COLS, 1, 0, buf);
634                         if(!search_winp)
635                                 goto END_WHILE;
636                         search_winp->key = ch;
637                         linkp = NULL;
638                         if(nt_get_search_text(buf, &search)){
639                                 if(search){
640                                         linkp = nt_search_all_board(
641                                                         app_2ch_model, search, &status_msg);
642                                         free(search);
643                                         buf[0] = '\0';
644                                 }
645                         }
646                         h_searched_thread = NULL;
647                         disp_state = disp_thread_search(search_winp, 
648                                         state, linkp, &h_searched_thread);
649                         ch = NT_KEY_NONE;
650                         if(h_searched_thread){
651                                 if(nt_set_sel_item(app_2ch_model,
652                                                 &h_sel_items_tmp, h_searched_thread, &status_msg)){
653                                         disp_state = DISP_STATE_RESLIST;
654                                         nt_2ch_selected_item_release_ref(h_sel_items);
655                                         h_sel_items = h_sel_items_tmp;
656                                         if(rwinp->data){
657                                                 free_reslist_ctx(rwinp->data);
658                                                 rwinp->data = NULL;
659                                         }
660                                         if(twinp->data){
661                                                 free_threadlist_ctx(twinp->data);
662                                                 twinp->data = NULL;
663                                         }
664                                         nt_searched_thread_release_ref(h_searched_thread);
665                                         h_searched_thread = NULL;
666                                         continue;
667                                 }
668                                 nt_searched_thread_release_ref(h_searched_thread);
669                                 h_searched_thread = NULL;
670                         }
671                         if(disp_state != DISP_STATE_SEARCH_THREAD){
672                                 continue;
673                         }
674                         break;
675                 case DISP_STATE_HISTORY:
676                         draw_title(scrp, L"履歴", WA_REVERSE);
677                         if(!history_winp)
678                                 history_winp = nt_disp_win_alloc(
679                                                 scrp, LINES-1, COLS, 1, 0, buf);
680                         if(!history_winp)
681                                 goto END_WHILE;
682                         history_winp->key = ch;
683                         h_searched_thread = NULL;
684                         state = disp_history(history_winp, state, app_2ch_model,
685                                                         db_handle, &h_searched_thread, &linkp);
686                         if(linkp){
687                                 nt_read_board_list(linkp);
688                                 nt_all_link_free(linkp, _2ch_selected_item_free);
689                         }
690                         if(DISP_CMD(state)){
691                                 ch = NT_KEY_NONE;
692                                 if(DISP_CMD(state) == DISP_CMD_SEL_THREAD){
693                                         assert(h_searched_thread);
694                                         if(nt_set_sel_item(app_2ch_model,
695                                                         &h_sel_items_tmp, h_searched_thread, &status_msg)){
696                                                 nt_2ch_selected_item_release_ref(h_sel_items);
697                                                 h_sel_items = h_sel_items_tmp;
698                                                 if(rwinp->data){
699                                                         free_reslist_ctx(rwinp->data);
700                                                         rwinp->data = NULL;
701                                                 }
702                                                 if(twinp->data){
703                                                         free_threadlist_ctx(twinp->data);
704                                                         twinp->data = NULL;
705                                                 }
706                                         }
707                                         nt_searched_thread_release_ref(h_searched_thread);
708                                         h_searched_thread = NULL;
709                                         disp_state = DISP_STATE_RESLIST;
710                                         state = DISP_STATE_HISTORY;
711                                         DISP_CLR_CMD(state);
712                                         continue;
713                                 }else if(DISP_CMD(state) == DISP_CMD_REENTER){
714                                         DISP_CLR_CMD(state);
715                                         continue;
716                                 }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
717                                         DISP_CLR_CMD(state);
718                                         if(history_winp->data){
719                                                 free_history_ctx(history_winp->data);
720                                                 history_winp->data = NULL;
721                                         }
722                                         continue;
723                                 }
724                         }
725                         if(state != DISP_STATE_HISTORY){
726                                 disp_state = state;
727                                 ch = NT_KEY_NONE;
728                                 continue;
729                         }
730                         break;
731                 case DISP_STATE_FAVORITE:
732                         draw_title(scrp, L"お気に入り", WA_REVERSE);
733                         if(!favorite_winp)
734                                 favorite_winp = nt_disp_win_alloc(
735                                                 scrp, LINES-1, COLS, 1, 0, buf);
736                         if(!favorite_winp)
737                                 goto END_WHILE;
738                         favorite_winp->key = ch;
739                         h_searched_thread = NULL;
740                         if(!favorite_winp->data){
741                                 linkp = nt_favorite_get_update_board_list(app_2ch_model, h_favorite);
742                                 if(linkp){
743                                         nt_read_board_list(linkp);
744                                         nt_all_link_free(linkp, _2ch_selected_item_free);
745                                 }
746                         }
747                         state = disp_favorite(favorite_winp, state, app_2ch_model,
748                                                         h_favorite, db_handle, 
749                                                         &handle,  &h_searched_thread);
750                         if(DISP_CMD(state)){
751                                 ch = NT_KEY_NONE;
752                                 if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_BOARD){
753                                         if(nt_favorite_board_remove(handle)){
754                                                 h_favorite_board = (nt_favorite_board_handle)handle;
755                                                 if(h_cloud){
756                                                         linkp = nt_link_add_data(NULL, 
757                                                                         (void*)nt_favorite_board_get_name(h_favorite_board));
758                                                         if(linkp){
759                                                                 nt_cloud_delete_lines_from_file(h_cloud, "fb.txt", linkp);
760                                                                 free(linkp);
761                                                         }
762                                                 }
763                                                 nt_favorite_board_release_ref(h_favorite_board);
764                                                 status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
765                                         }else{
766                                                 status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
767                                         }
768                                 }else if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_THREAD){
769                                         if(nt_favorite_thread_remove(handle)){
770                                                 h_favorite_thread = (nt_favorite_thread_handle)handle;
771                                                 if(h_cloud){
772                                                         linkp = NULL;
773                                                         if(nt_favorite_retrieve_thread(h_favorite_thread, &linkp)){
774                                                                 nt_cloud_delete_lines_from_file(h_cloud, "ft.txt", linkp);
775                                                                 nt_all_link_free(linkp, free);
776                                                         }
777                                                 }
778                                                 nt_favorite_thread_release_ref(h_favorite_thread);
779                                                 status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
780                                         }else{
781                                                 status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
782                                         }
783                                 }else if(DISP_CMD(state) == DISP_CMD_SEL_BOARD ||
784                                                 DISP_CMD(state) == DISP_CMD_SEL_THREAD){
785                                         assert(h_searched_thread);
786                                         if(nt_set_sel_item(app_2ch_model,
787                                                         &h_sel_items_tmp, h_searched_thread, &status_msg)){
788                                                 disp_state = (DISP_CMD(state) == DISP_CMD_SEL_BOARD)
789                                                         ? DISP_STATE_THREADTITLE : DISP_STATE_RESLIST;
790                                                 state = DISP_STATE_FAVORITE;
791                                                 nt_2ch_selected_item_release_ref(h_sel_items);
792                                                 h_sel_items = h_sel_items_tmp;
793                                                 if(rwinp->data){
794                                                         free_reslist_ctx(rwinp->data);
795                                                         rwinp->data = NULL;
796                                                 }
797                                                 if(twinp->data){
798                                                         free_threadlist_ctx(twinp->data);
799                                                         twinp->data = NULL;
800                                                 }
801                                         }
802                                         nt_searched_thread_release_ref(h_searched_thread);
803                                         h_searched_thread = NULL;
804                                 }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
805                                         state = DISP_STATE_FAVORITE;
806                                         ch = NT_KEY_NONE;
807                                         if(favorite_winp->data){
808                                                 free_favorite_ctx(favorite_winp->data);
809                                                 favorite_winp->data = NULL;
810                                         }
811                                         status_msg = NT_INFO_REFRESH_FAVORITE_SUCCESS;
812                                         wclear(scrp);
813                                         continue;
814                                 }else if(h_cloud){
815                                         if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
816                                                         DISP_CMD(state) == DISP_CMD_UPLOAD_BOARDS){
817                                                 status_msg = NT_ERR_MSG_UPLOAD_FAVORITE_FAILED;
818                                                 linkp = nt_favorite_retrieve_boards(h_favorite);
819                                                 if(linkp){
820                                                         if(nt_cloud_upload_file(h_cloud, "fb.txt", linkp)){
821                                                                 status_msg = NT_INFO_UPLOAD_FAVORITE_SUCCEEDED;
822                                                         }
823                                                         nt_all_link_free(linkp, free);
824                                                 }
825                                         }
826                                         if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
827                                                         DISP_CMD(state) == DISP_CMD_UPLOAD_THREADS){
828                                                 if(nt_favorite_retrieve_threads(h_favorite, 
829                                                                 &linkp, &linkp2)){
830                                                         if(linkp)
831                                                                 nt_all_link_free(linkp, free);
832                                                         if(linkp2){
833                                                                 if(nt_cloud_upload_file(h_cloud, "ft.txt", linkp2)){
834                                                                         status_msg = NT_INFO_UPLOAD_FAVORITE_SUCCEEDED;
835                                                                 }
836                                                                 nt_all_link_free(linkp2, free);
837                                                         }
838                                                 }
839                                         }
840                                         if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
841                                                         DISP_CMD(state) == DISP_CMD_UPLOAD_NG_FILES){
842                                                 if(nt_ng_word_upload_cloud(h_cloud, h_ng_word)){
843                                                         status_msg = NT_INFO_UPLOAD_FAVORITE_SUCCEEDED;
844                                                 }
845                                         }
846                                         disp_state = state = DISP_STATE_FAVORITE;
847                                 }else{
848                                         disp_state = state = DISP_STATE_FAVORITE;
849                                 }
850                                 continue;
851                         }else if(state != DISP_STATE_FAVORITE){
852                                 ch = NT_KEY_NONE;
853                                 disp_state = state;
854                                 state = DISP_STATE_FAVORITE;
855                                 continue;
856                         }else{
857                                 disp_state = DISP_STATE_FAVORITE;
858                         }
859                         break;
860                 default:
861                         goto END_WHILE;
862                 }/* end switch*/
863
864                 if(status_msg){
865                         print_error(scrp, status_msg);
866                         status_msg = NULL;
867                 }
868
869                 move(LINES-1,COLS-1);
870                 touchwin(scrp);
871                 wrefresh(scrp);
872                 
873                 timeout(NT_MAINLOOP_POLLING_INTERVAL);
874                 do{
875                         ch = getch();
876                         if(ch == ERR){
877                                 async_data = nt_pthread_get_result_from_que();
878                                 if(async_data.code == NT_PTHREAD_RESULT_UPDATE_BOARD){
879                                         ch = NT_KEY_CMD_BOARD_UPDATE;
880                                         //fprintf(stderr, "Async result recieved.!\n");
881                                 }else if(async_data.code == NT_PTHREAD_RESULT_UPDATE_FAVORITE){
882                                         ch = NT_KEY_CMD_FAVORITE_UPDATE;
883                                         //fprintf(stderr, "Async result recieved.!\n");
884                                 }else{
885                                         h_timer = nt_timer_ring_a_bell();
886                                         if(h_timer){
887                                                 switch(nt_timer_get_id(h_timer)){
888                                                 case TIMER_ID_AUTO_SCROLL:
889                                                         ch = NT_KEY_CMD_AUTO_SCROLL;
890                                                         break;
891                                                 case TIMER_ID_AUTO_UPDATE:
892                                                         linkp = nt_favorite_get_update_board_list(
893                                                                         app_2ch_model, h_favorite);
894                                                         if(linkp){
895                                                                 nt_read_board_list(linkp);
896                                                                 nt_all_link_free(linkp, _2ch_selected_item_free);
897                                                                 //fprintf(stderr, "Update request calling.!\n");
898                                                         }
899                                                         break;
900                                                 }
901                                                 nt_timer_release_ref(h_timer);
902                                         }
903                                 }
904                         }
905                 }while(ch == '\n' || ch == '\r' || ch == ERR);
906                 timeout(-1);
907                 
908                 switch(ch){
909                 case NT_KEY_UP:
910                 case KEY_UP:
911                 case NT_KEY_DOWN:
912                 case KEY_DOWN:
913                 case NT_KEY_LEFT:
914                 case NT_KEY_RIGHT:
915                 case KEY_RIGHT:
916                 case NT_KEY_PAGEUP:
917                 case KEY_PPAGE:
918                 case NT_KEY_PAGEDOWN:
919                 case KEY_NPAGE:
920                 case NT_KEY_SELECT:
921                 case NT_KEY_ADD:
922                 case NT_KEY_DEL:
923                 case NT_KEY_BOTTOM:
924                 case KEY_END:
925                 case NT_KEY_REFRESH:
926                         break;
927                 case NT_KEY_CLOSE:
928                 case KEY_LEFT:
929                         wclear(scrp);
930                         break;
931                 case KEY_HOME:
932                         ch = NT_KEY_COMMAND1;
933                         nt_add_wch(scrp,ch,0);
934                         strncpy(buf,"1",2);
935                         break;
936                 case NT_KEY_COMMAND1:
937                 case NT_KEY_COMMAND2:
938                 case NT_KEY_COMMAND3:
939                         echo();
940                         nocbreak();
941                         wch = ch;
942                         move(LINES-1,0);
943                         nt_add_wch(scrp,wch,0);
944                         getstr(buf);
945                         cbreak();
946                         noecho();
947                         break;
948                 case NT_KEY_ERASE:
949                         wclear(scrp);
950                         break;
951                 case NT_KEY_QUIT:
952                         result = TRUE;
953                         goto END_WHILE;
954                 }/* end switch*/
955         }/* end while */
956 END_WHILE:
957         if(h_timer_auto_update)
958                 nt_timer_release_ref(h_timer_auto_update);
959         if(h_timer_auto_scroll)
960                 nt_timer_release_ref(h_timer_auto_scroll);
961         if(cookiep)
962                 nt_unload_cookie(cookiep);
963         if(marup)
964                 nt_maru_2ch_free(marup);
965         if(h_write_data)
966                 nt_write_data_release_ref(h_write_data);
967         if(h_searched_thread)
968                 nt_searched_thread_release_ref(h_searched_thread);
969         nt_2ch_selected_item_release_ref(h_sel_items);
970         free_board_menu_ctx(bwinp->data);
971         free_threadlist_ctx(twinp->data);
972         free_reslist_ctx(rwinp->data);
973         if(history_winp){
974                 if(history_winp->data)
975                         free_history_ctx(history_winp->data);
976                 nt_disp_win_free(history_winp);
977         }
978         if(search_winp){
979                 if(search_winp->data)
980                         free_search_thread_ctx(search_winp->data);
981                 nt_disp_win_free(search_winp);
982         }
983         if(favorite_winp){
984                 if(favorite_winp->data)
985                         free_favorite_ctx(favorite_winp->data);
986                 nt_disp_win_free(favorite_winp);
987         }
988         nt_disp_win_free(bwinp);
989         nt_disp_win_free(twinp);
990         nt_disp_win_free(rwinp);
991         
992         return result;
993 }
994
995
996
997 static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr)
998 {
999         move(0,0);
1000         int  num;
1001         num = nt_get_wc_count_within_colmns(title, COLS-1);
1002         if(num == 0)
1003                 return 0;
1004         
1005         nt_add_wnch(wp, L' ', attr, COLS);
1006         move(0,1);
1007         nt_add_wnstr(wp, title, WA_REVERSE, COLS - 1);
1008         return 1;
1009 }
1010
1011
1012
1013 static void print_error(WINDOW *wp, const wchar_t *msg)
1014 {
1015         move(LINES-1,0);
1016         nt_add_wstr(wp, msg, 0);
1017 }
1018