Commit MetaInfo

修订版88caa00a0302c2555d8b568f894eaf59e3d99f3f (tree)
时间2014-01-10 00:20:37
作者Akira <akohta001@gmai...>
CommiterAkira

Log Message

v1.0.2.5
Support: history view.

更改概述

差异

--- a/Makefile
+++ b/Makefile
@@ -5,14 +5,15 @@
55
66 #Option for development
77 #CFLAGS = -g -Wall -DDEBUG ${DEFS} ${CDEF} -DNT_CLOUD
8-#CFLAGS = -g -Wall -DDEBUG ${DEFS} ${CDEF} -DNT_CLOUD -DNT_NET_IPV6
8+CFLAGS = -g -Wall -DDEBUG ${DEFS} ${CDEF} -DNT_CLOUD -DNT_NET_IPV6
99 #Option for release
10-CFLAGS = -Wall ${DEFS} ${CDEF} -DNT_CLOUD -DNT_NET_IPV6
10+#CFLAGS = -Wall ${DEFS} ${CDEF} -DNT_CLOUD -DNT_NET_IPV6
1111
1212 CDEF = -D_REENTRANT -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE=700 -D_ISOC99_SOURCE
1313
1414 OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
1515 ${OBJ_DIR}/env.o \
16+ ${OBJ_DIR}/server_main.o \
1617 ${OBJ_DIR}/print_help.o \
1718 ${OBJ_DIR}/cloud/nt_cloud.o \
1819 ${OBJ_DIR}/cloud/nt_cloud2.o \
@@ -48,6 +49,7 @@ OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
4849 ${OBJ_DIR}/ui/disp_reslist.o \
4950 ${OBJ_DIR}/ui/disp_search_thread.o \
5051 ${OBJ_DIR}/ui/disp_favorite.o \
52+ ${OBJ_DIR}/ui/disp_history.o \
5153 ${OBJ_DIR}/ui/disp_win.o \
5254 ${OBJ_DIR}/ui/disp_editor.o \
5355 ${OBJ_DIR}/ui/disp_html_result.o \
@@ -141,6 +143,10 @@ $(OBJ_DIR)/main.o : ${SRC_DIR}/main.c ${INC_FILES}
141143 @ ${SHELL} prepare_proj.sh
142144 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
143145
146+$(OBJ_DIR)/server_main.o : ${SRC_DIR}/server_main.c ${INC_FILES}
147+ @ ${SHELL} prepare_proj.sh
148+ ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
149+
144150 $(OBJ_DIR)/env.o : ${SRC_DIR}/env.c ${INC_FILES}
145151 @ ${SHELL} prepare_proj.sh
146152 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
@@ -281,6 +287,10 @@ $(OBJ_DIR)/ui/disp_favorite.o : ${SRC_DIR}/ui/disp_favorite.c ${INC_FILES}
281287 @ ${SHELL} prepare_proj.sh
282288 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
283289
290+$(OBJ_DIR)/ui/disp_history.o : ${SRC_DIR}/ui/disp_history.c ${INC_FILES}
291+ @ ${SHELL} prepare_proj.sh
292+ ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
293+
284294 $(OBJ_DIR)/ui/disp_search_thread.o : ${SRC_DIR}/ui/disp_search_thread.c ${INC_FILES}
285295 @ ${SHELL} prepare_proj.sh
286296 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
--- a/Makefile.in
+++ b/Makefile.in
@@ -13,6 +13,7 @@ CDEF = -D_REENTRANT -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE=700 -D_ISOC99_SOURC
1313
1414 OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
1515 ${OBJ_DIR}/env.o \
16+ ${OBJ_DIR}/server_main.o \
1617 ${OBJ_DIR}/print_help.o \
1718 ${OBJ_DIR}/cloud/nt_cloud.o \
1819 ${OBJ_DIR}/cloud/nt_cloud2.o \
@@ -48,6 +49,7 @@ OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
4849 ${OBJ_DIR}/ui/disp_reslist.o \
4950 ${OBJ_DIR}/ui/disp_search_thread.o \
5051 ${OBJ_DIR}/ui/disp_favorite.o \
52+ ${OBJ_DIR}/ui/disp_history.o \
5153 ${OBJ_DIR}/ui/disp_win.o \
5254 ${OBJ_DIR}/ui/disp_editor.o \
5355 ${OBJ_DIR}/ui/disp_html_result.o \
@@ -141,6 +143,10 @@ $(OBJ_DIR)/main.o : ${SRC_DIR}/main.c ${INC_FILES}
141143 @ ${SHELL} prepare_proj.sh
142144 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
143145
146+$(OBJ_DIR)/server_main.o : ${SRC_DIR}/server_main.c ${INC_FILES}
147+ @ ${SHELL} prepare_proj.sh
148+ ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
149+
144150 $(OBJ_DIR)/env.o : ${SRC_DIR}/env.c ${INC_FILES}
145151 @ ${SHELL} prepare_proj.sh
146152 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
@@ -281,6 +287,10 @@ $(OBJ_DIR)/ui/disp_favorite.o : ${SRC_DIR}/ui/disp_favorite.c ${INC_FILES}
281287 @ ${SHELL} prepare_proj.sh
282288 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
283289
290+$(OBJ_DIR)/ui/disp_history.o : ${SRC_DIR}/ui/disp_history.c ${INC_FILES}
291+ @ ${SHELL} prepare_proj.sh
292+ ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
293+
284294 $(OBJ_DIR)/ui/disp_search_thread.o : ${SRC_DIR}/ui/disp_search_thread.c ${INC_FILES}
285295 @ ${SHELL} prepare_proj.sh
286296 ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
11
2- ntch version 1.0.2.3
2+ ntch version 1.0.2.5
33
44 This file is part of ntch.
55
@@ -21,7 +21,7 @@
2121 hlhex(SORCE FORGE.JP ID)
2222 takeutch-kemeco(GitHub ID)
2323
24- Copyright 2013 Akira Ohta (akohta001@gmail.com)
24+ Copyright 2013,2014 Akira Ohta (akohta001@gmail.com)
2525
2626 Linux用 2ch専用ブラウザー
2727
--- a/config.h
+++ b/config.h
@@ -141,7 +141,7 @@
141141 #define PACKAGE_NAME "ntch"
142142
143143 /* Define to the full name and version of this package. */
144-#define PACKAGE_STRING "ntch 1.0.2.4"
144+#define PACKAGE_STRING "ntch 1.0.2.5"
145145
146146 /* Define to the one symbol short name of this package. */
147147 #define PACKAGE_TARNAME "ntch"
@@ -150,7 +150,7 @@
150150 #define PACKAGE_URL "https://sourceforge.jp/projects/ntch/"
151151
152152 /* Define to the version of this package. */
153-#define PACKAGE_VERSION "1.0.2.4"
153+#define PACKAGE_VERSION "1.0.2.5"
154154
155155 /* Define to 1 if you have the ANSI C header files. */
156156 #define STDC_HEADERS 1
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
11 #! /bin/sh
22 # Guess values for system-dependent variables and create Makefiles.
3-# Generated by GNU Autoconf 2.69 for ntch 1.0.2.4.
3+# Generated by GNU Autoconf 2.69 for ntch 1.0.2.5.
44 #
55 # Report bugs to <akohta001@gmail.com>.
66 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
580580 # Identity of this package.
581581 PACKAGE_NAME='ntch'
582582 PACKAGE_TARNAME='ntch'
583-PACKAGE_VERSION='1.0.2.4'
584-PACKAGE_STRING='ntch 1.0.2.4'
583+PACKAGE_VERSION='1.0.2.5'
584+PACKAGE_STRING='ntch 1.0.2.5'
585585 PACKAGE_BUGREPORT='akohta001@gmail.com'
586586 PACKAGE_URL='https://sourceforge.jp/projects/ntch/'
587587
@@ -1230,7 +1230,7 @@ if test "$ac_init_help" = "long"; then
12301230 # Omit some internal or obsolete options to make the list less imposing.
12311231 # This message is too long to be a string in the A/UX 3.1 sh.
12321232 cat <<_ACEOF
1233-\`configure' configures ntch 1.0.2.4 to adapt to many kinds of systems.
1233+\`configure' configures ntch 1.0.2.5 to adapt to many kinds of systems.
12341234
12351235 Usage: $0 [OPTION]... [VAR=VALUE]...
12361236
@@ -1291,7 +1291,7 @@ fi
12911291
12921292 if test -n "$ac_init_help"; then
12931293 case $ac_init_help in
1294- short | recursive ) echo "Configuration of ntch 1.0.2.4:";;
1294+ short | recursive ) echo "Configuration of ntch 1.0.2.5:";;
12951295 esac
12961296 cat <<\_ACEOF
12971297
@@ -1372,7 +1372,7 @@ fi
13721372 test -n "$ac_init_help" && exit $ac_status
13731373 if $ac_init_version; then
13741374 cat <<\_ACEOF
1375-ntch configure 1.0.2.4
1375+ntch configure 1.0.2.5
13761376 generated by GNU Autoconf 2.69
13771377
13781378 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1795,7 +1795,7 @@ cat >config.log <<_ACEOF
17951795 This file contains any messages produced by compilers while
17961796 running configure, to aid debugging if configure makes a mistake.
17971797
1798-It was created by ntch $as_me 1.0.2.4, which was
1798+It was created by ntch $as_me 1.0.2.5, which was
17991799 generated by GNU Autoconf 2.69. Invocation command line was
18001800
18011801 $ $0 $@
@@ -4797,7 +4797,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
47974797 # report actual input values of CONFIG_FILES etc. instead of their
47984798 # values after options handling.
47994799 ac_log="
4800-This file was extended by ntch $as_me 1.0.2.4, which was
4800+This file was extended by ntch $as_me 1.0.2.5, which was
48014801 generated by GNU Autoconf 2.69. Invocation command line was
48024802
48034803 CONFIG_FILES = $CONFIG_FILES
@@ -4864,7 +4864,7 @@ _ACEOF
48644864 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
48654865 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
48664866 ac_cs_version="\\
4867-ntch config.status 1.0.2.4
4867+ntch config.status 1.0.2.5
48684868 configured by $0, generated by GNU Autoconf 2.69,
48694869 with options \\"\$ac_cs_config\\"
48704870
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
22 # Process this file with autoconf to produce a configure script.
33
44 AC_PREREQ([2.69])
5-AC_INIT([ntch], [1.0.2.4], [akohta001@gmail.com],[ntch],[https://sourceforge.jp/projects/ntch/])
5+AC_INIT([ntch], [1.0.2.5], [akohta001@gmail.com],[ntch],[https://sourceforge.jp/projects/ntch/])
66 AC_CONFIG_SRCDIR([src/main.c])
77 AC_CONFIG_HEADERS([config.h])
88
--- a/help.txt
+++ b/help.txt
@@ -1,5 +1,5 @@
11
2- ntch version 1.0.2.4
2+ ntch version 1.0.2.5
33
44 This file is part of ntch.
55
@@ -21,7 +21,7 @@
2121 hlhex(SORCE FORGE.JP ID)
2222 takeutch-kemeco(GitHub ID)
2323
24- Copyright 2013 Akira Ohta (akohta001@gmail.com)
24+ Copyright 2013,2014 Akira Ohta (akohta001@gmail.com)
2525
2626 Linux用 2ch専用ブラウザー
2727
@@ -55,17 +55,20 @@ Linux用 2ch専用ブラウザー
5555 c 前画面に戻る
5656 f ページダウン
5757 b ページアップ
58- z 画面リフレッシュ
58+ r 画面リフレッシュ
59+ z 画面構造ツリーを上に移動する
60+ cキーは直前の画面に戻りますがzキーは
61+ 例えばお気に入りからスレッドを開いた時にcキーはお気に入り画面に
62+ 戻りますが、zキーはスレタイ一覧画面に遷移します
63+ スレタイ一覧画面ではzキーは直前の画面に関係なく板メニューに遷移
64+ します。
5965 :search :se [検索文字列] 全板検索
6066 指定された文字列をキーにして板全体からスレッドを検索します
6167 文字列の指定はオプションで、未指定時には空の全板検索画面に
6268 遷移します
6369 :favorite :f お気に入りの表示
64- リソースファイルの設定で起動時にお気に入りを表示
65- することも出来ます
66- 実行ユーザーのホームディレクトリに.ntchrcファイルを
67- 作成して、以下の書式で指定して下さい。
68- show=favorite
70+ :history :h 履歴の表示(表示したスレッドの履歴を表示します)
71+
6972
7073 板メニュー
7174 h 左カラムへ移動
@@ -89,9 +92,6 @@ Linux用 2ch専用ブラウザー
8992 read 取得済みスレッド優先
9093 unread 未読数順
9194 リソースファイルに初期値を指定出来ます
92- 実行ユーザーのホームディレクトリに.ntchrcファイルを
93- 作成して、以下の書式で指定して下さい。
94- sort=[number | read | unread]
9595 :d :del [スレ番号 | * ] 指定したスレッドの取得済みログを削除します
9696 * 表示している板の全ての取得済ログを削除
9797 スレ番号 以下の2ch形式の番号指定が使えます
@@ -128,11 +128,6 @@ Linux用 2ch専用ブラウザー
128128 内容を確認してエディターを終了して下さい。
129129 書込確認を中止する方法が(現時点で)ないでの
130130 その場合は強制終了して下さい。
131- ●2chビューアーのIDを指定して書込が出来ます。
132- 実行ユーザーのホームディレクトリに.ntchrcファイルを
133- 作成して、以下の書式でIDとパスワードを指定して下さい。
134- maru-id=[2chビューアーのユーザーID]
135- maru-pw=[2chビューアーのパスワード]
136131 r スレッドを更新する
137132 /[検索文字列] 指定文字列の後方検索
138133 ?[検索文字列] 指定文字列の前方検索
@@ -144,17 +139,45 @@ Linux用 2ch専用ブラウザー
144139 :a :autoscroll 自動スクロール
145140 j,k,f,bキー以外の入力で自動スクロール解除
146141 k,bキーで反転スクロール
147- .ntchrcファイルにスクロールスピードを指定出来ます
148- 以下の書式でIDとパスワードを指定して下さい。
149- auto-scroll-interval=[数字] ミリ秒で指定(標準値500msec)
150142
151143 お気に入り一覧
152144 d 選択項目をお気に入りから削除
153145 l 直前に表示したお気に入りを再表示
154146 h スレッド選択時にそのスレッドの上位の板を表示
155- .ntchrcファイルにお気に入りの更新頻度を指定出来ます
156- 以下の書式でIDとパスワードを指定して下さい。
157- auto-update-interval=[数字] ミリ秒で指定(標準値60000msec)
147+
148+履歴一覧
149+ :limit :l [n[,n]] 表示履歴範囲を指定します
150+ 例1 :l 50 履歴データーベースの新しいものから50件を取得します
151+ 例2 :l 10,30 履歴データーベースの新しいものから10件をスキップして
152+ 30件を取得します
153+ 例3 :l 履歴データーベースの直前のスキップ位置に表示範囲数を
154+ ずらして同じ件数を取得します
155+ SQLの文法では 例1 :l limit 例2 :l offset,limit
156+ 例3 直前のoffsetに直前のlimitを加算して、同じlimit値で
157+ 例2と同様に検索します(次ページの動作)
158+
159+リソースファイルの設定
160+ 実行ユーザーのホームディレクトリに.ntchrcファイルを作成します
161+ 項目と設定値を=で繋げて記述します
162+
163+起動時の画面の指定
164+未指定 板メニュー
165+show=favorite お気に入り画面
166+show=history 履歴画面
167+
168+お気に入りの自動更新頻度
169+auto-update-interval=[数字] ミリ秒で指定(標準値60000msec)
170+
171+レス画面の自動スクロール速度
172+auto-scroll-interval=[数字] ミリ秒で指定(標準値500msec)
173+
174+スレッドタイトル一覧画面の表示順序の初期値
175+sort=[number | read | unread]
176+ number レス番号順
177+ read 既読を上に表示
178+ unread 未読数順
179+
180+行の先頭に # を指定するとその行はコメントとして扱われます
158181
159182 ---------------------------------------------
160183
--- a/src/_2ch/_2ch.c
+++ b/src/_2ch/_2ch.c
@@ -152,7 +152,7 @@ BOOL nt_read_thread(nt_2ch_selected_item_handle h_select)
152152 wchar_t *server_name, *board_name;
153153 nt_board_tp boardp;
154154 nt_thread_tp threadp;
155- int len;
155+ int len, res_no;
156156 iconv_t icd;
157157 FILE *fp_src;
158158 char s_src[S_SIZE*sizeof(wchar_t)];
@@ -262,7 +262,9 @@ BOOL nt_read_thread(nt_2ch_selected_item_handle h_select)
262262 }
263263 nt_thread_clear_children(&threadp->handle);
264264 threadp->num_res = 0;
265+ res_no = 0;
265266 while(1){
267+ res_no++;
266268 if(feof(fp_src))
267269 break;
268270 s_src[0] = '\0';
@@ -282,7 +284,7 @@ BOOL nt_read_thread(nt_2ch_selected_item_handle h_select)
282284 }
283285 *((wchar_t*)p_dst) = L'\0';
284286 if(!is_matchi_bbs)
285- parse_thread(&threadp->handle, (const wchar_t*)s_dst);
287+ parse_thread(&threadp->handle, (const wchar_t*)s_dst, res_no);
286288 else
287289 parse_thread_machi_bbs(&threadp->handle, (const wchar_t*)s_dst);
288290 }
--- a/src/_2ch/parse_2ch.c
+++ b/src/_2ch/parse_2ch.c
@@ -31,7 +31,7 @@
3131 static nt_category_handle get_last_category(nt_2ch_model_tp modelp);
3232
3333
34-BOOL parse_thread(nt_thread_handle h_thread, const wchar_t *linep)
34+BOOL parse_thread(nt_thread_handle h_thread, const wchar_t *linep, int res_no)
3535 {
3636 wchar_t buf[1024*3+1];
3737 nt_res_handle h_res;
@@ -80,7 +80,7 @@ BOOL parse_thread(nt_thread_handle h_thread, const wchar_t *linep)
8080 nt_res_release_ref(h_res);
8181
8282 resp = (nt_res_tp)h_res;
83- resp->seq_no = ((nt_thread_tp)h_thread)->num_res;
83+ resp->seq_no = res_no;//((nt_thread_tp)h_thread)->num_res;
8484 return TRUE;
8585 }
8686
--- a/src/cloud/nt_cloud2.c
+++ b/src/cloud/nt_cloud2.c
@@ -492,6 +492,7 @@ BOOL nt_cloud_query_favorite_attributes_async(nt_cloud_handle handle,
492492 nt_all_link_free(linkp, NULL);
493493 return FALSE;
494494 }
495+ nt_pthread_release_ref(h_pthread);
495496 return TRUE;
496497 }
497498
--- a/src/env.c
+++ b/src/env.c
@@ -1,4 +1,4 @@
1-/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
1+/* Copyright 2013,2014 Akira Ohta (akohta001@gmail.com)
22 This file is part of ntch.
33
44 The ntch is free software: you can redistribute it and/or modify
@@ -49,6 +49,7 @@ int NT_PTHREAD_POOL_SIZE;
4949 int NT_PTHREAD_POOL_QUEUE_SIZE;
5050 int NT_AUTO_SCROLL_INTERVAL;
5151 int NT_AUTO_UPDATE_INTERVAL;
52+int APP_MODE;
5253
5354 char *RFC2898_SALT;
5455 int RFC2898_ITERATION;
@@ -73,6 +74,7 @@ struct option longopts[] = {
7374 {"editor", 1, NULL, 'e'},
7475 {"out-path", 1, NULL, 'o'},
7576 {"pem", 1, NULL, 'p'},
77+ {"server", 2, NULL, 's'},
7678 {NULL, 0, NULL, 0}
7779 };
7880
@@ -96,6 +98,8 @@ int set_option(int argc, char* argv[])
9698 uid_t uid;
9799 struct passwd *pw;
98100 char buf[256];
101+
102+ APP_MODE = NT_APP_MODE_CLIENT;
99103
100104 MARU_ID = NULL;
101105 MARU_PW = NULL;
@@ -142,7 +146,7 @@ int set_option(int argc, char* argv[])
142146 }
143147
144148 while((opt = getopt_long(
145- argc, argv, "hvro:p:", longopts, NULL)) != -1){
149+ argc, argv, "hvro:p:s::", longopts, NULL)) != -1){
146150
147151 switch(opt){
148152 case 'r':
@@ -174,6 +178,9 @@ int set_option(int argc, char* argv[])
174178 break;
175179 strcpy(CA_FILE_PATH, optarg);
176180 break;
181+ case 's':
182+ APP_MODE = NT_APP_MODE_SERVER;
183+ break;
177184 default:
178185 break;
179186 }
@@ -246,6 +253,8 @@ extern BOOL read_resource(const char *path)
246253 break;
247254 if(0 == strcmp(init_disp, "favorite")){
248255 INIT_DISP_STATE = NT_INTI_DISP_FAVORITE;
256+ }else if(0 == strcmp(init_disp, "history")){
257+ INIT_DISP_STATE = NT_INTI_DISP_HISTORY;
249258 }
250259 free(init_disp);
251260 continue;
--- a/src/inc/_2ch/model_2ch.h
+++ b/src/inc/_2ch/model_2ch.h
@@ -183,7 +183,7 @@ extern wchar_t* nt_read_thread_title(nt_board_handle h_board,
183183 extern BOOL parse_board_menu(nt_2ch_model_handle h_model,
184184 const wchar_t *linep);
185185 extern BOOL parse_board(nt_board_handle h_board, const wchar_t *linep);
186-extern BOOL parse_thread(nt_thread_handle h_board, const wchar_t *linep);
186+extern BOOL parse_thread(nt_thread_handle h_board, const wchar_t *linep, int res_no);
187187 extern BOOL parse_thread_machi_bbs(nt_thread_handle h_board, const wchar_t *linep);
188188 extern wchar_t* parse_thread_title(const wchar_t *linep);
189189
--- a/src/inc/config.h
+++ b/src/inc/config.h
@@ -141,7 +141,7 @@
141141 #define PACKAGE_NAME "ntch"
142142
143143 /* Define to the full name and version of this package. */
144-#define PACKAGE_STRING "ntch 1.0.2.4"
144+#define PACKAGE_STRING "ntch 1.0.2.5"
145145
146146 /* Define to the one symbol short name of this package. */
147147 #define PACKAGE_TARNAME "ntch"
@@ -150,7 +150,7 @@
150150 #define PACKAGE_URL "https://sourceforge.jp/projects/ntch/"
151151
152152 /* Define to the version of this package. */
153-#define PACKAGE_VERSION "1.0.2.4"
153+#define PACKAGE_VERSION "1.0.2.5"
154154
155155 /* Define to 1 if you have the ANSI C header files. */
156156 #define STDC_HEADERS 1
--- a/src/inc/env.h
+++ b/src/inc/env.h
@@ -1,4 +1,4 @@
1-/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
1+/* Copyright 2013,2014 Akira Ohta (akohta001@gmail.com)
22 This file is part of ntch.
33
44 The ntch is free software: you can redistribute it and/or modify
@@ -44,16 +44,23 @@ extern int NT_PTHREAD_POOL_QUEUE_SIZE;
4444 extern int NT_AUTO_UPDATE_INTERVAL;
4545 extern int NT_AUTO_SCROLL_INTERVAL;
4646
47+extern int APP_MODE;
48+
49+
4750 extern char EDITOR_CMD[];
4851 extern char *MARU_ID;
4952 extern char *MARU_PW;
5053
54+#define NT_APP_MODE_SERVER 1
55+#define NT_APP_MODE_CLIENT 2
56+
5157 #define NT_THREAD_SORT_BY_NUMBER 1
5258 #define NT_THREAD_SORT_BY_UNREAD 2
5359 #define NT_THREAD_SORT_BY_READ 3
5460
5561 #define NT_INTI_DISP_BOARDMENU 1
5662 #define NT_INTI_DISP_FAVORITE 2
63+#define NT_INTI_DISP_HISTORY 3
5764
5865 #define NT_KEY_NONE (-1)
5966 #define NT_KEY_UP 'k'
@@ -99,6 +106,8 @@ extern char *MARU_PW;
99106 #define NT_COMMAND1_SEARCH_2 "se"
100107 #define NT_COMMAND1_FAVORITE_1 "favorite"
101108 #define NT_COMMAND1_FAVORITE_2 "f"
109+#define NT_COMMAND1_HISTORY_1 "history"
110+#define NT_COMMAND1_HISTORY_2 "h"
102111 #define NT_COMMAND1_AUTOSCROLL_1 "autoscroll"
103112 #define NT_COMMAND1_AUTOSCROLL_2 "a"
104113 #define NT_COMMAND1_UPLOAD_1 "upload"
@@ -106,6 +115,8 @@ extern char *MARU_PW;
106115 #define NT_COMMAND1_UPLOAD_BOARD2 "b"
107116 #define NT_COMMAND1_UPLOAD_THREAD1 "thread"
108117 #define NT_COMMAND1_UPLOAD_THREAD2 "t"
118+#define NT_COMMAND1_LIMIT_1 "limit"
119+#define NT_COMMAND1_LIMIT_2 "l"
109120
110121 extern int set_option(int argc, char* argv[]);
111122
--- a/src/inc/ui/disp.h
+++ b/src/inc/ui/disp.h
@@ -44,21 +44,23 @@
4444 #define DISP_STATE_RESLIST 3
4545 #define DISP_STATE_EDITOR 4
4646 #define DISP_STATE_HTML_RESULT 5
47-#define DISP_STATE_REFRESH 6
48-#define DISP_STATE_SEARCH_THREAD 7
49-#define DISP_STATE_FAVORITE 8
47+#define DISP_STATE_SEARCH_THREAD 6
48+#define DISP_STATE_FAVORITE 7
49+#define DISP_STATE_HISTORY 8
5050
5151 #define DISP_CMD_ADD_FAVORITE (1*256)
5252 #define DISP_CMD_DEL_FAVORITE_BOARD (2*256)
5353 #define DISP_CMD_DEL_FAVORITE_GRP (3*256)
5454 #define DISP_CMD_DEL_FAVORITE_THREAD (4*256)
55-#define DISP_CMD_SEL_FAVORITE_BOARD (5*256)
56-#define DISP_CMD_SEL_FAVORITE_THREAD (6*256)
55+#define DISP_CMD_SEL_BOARD (5*256)
56+#define DISP_CMD_SEL_THREAD (6*256)
5757 #define DISP_CMD_UPDATE_FAVORITE (7*256)
5858 #define DISP_CMD_AUTO_SCROLL (8*256)
5959 #define DISP_CMD_UPLOAD_ALL (9*256)
6060 #define DISP_CMD_UPLOAD_BOARDS (10*256)
6161 #define DISP_CMD_UPLOAD_THREADS (11*256)
62+#define DISP_CMD_REFRESH (12*256)
63+#define DISP_CMD_REENTER (13*256)
6264
6365 extern int disp_board_menu(nt_window_tp wp,
6466 nt_2ch_model_handle h_model, nt_2ch_selected_item_handle h_select);
@@ -73,12 +75,18 @@ extern int disp_favorite(nt_window_tp wp, int prev_state,
7375 nt_2ch_model_handle h_model, nt_favorite_handle h_favorite,
7476 nt_usr_db_handle h_usr_db,
7577 void **result_hadle, nt_searched_thread_handle *h_sel_threadp);
78+extern int disp_history(nt_window_tp wp, int prev_state,
79+ nt_2ch_model_handle h_model,
80+ nt_usr_db_handle h_usr_db,
81+ nt_searched_thread_handle *h_sel_threadp,
82+ nt_link_tp *update_board_list);
7683 extern void free_board_menu_ctx(void *ptr);
7784 extern void init_threadlist_ctx(void *ptr);
7885 extern void free_threadlist_ctx(void *ptr);
7986 extern void free_reslist_ctx(void *ptr);
8087 extern void free_search_thread_ctx(void *ptr);
8188 extern void free_favorite_ctx(void *ptr);
89+extern void free_history_ctx(void *ptr);
8290 extern BOOL disp_editor(nt_write_data_handle h_write_data);
8391 extern int disp_html_result(nt_write_data_handle h_write_data);
8492
--- a/src/inc/usr/usr_db_t.h
+++ b/src/inc/usr/usr_db_t.h
@@ -26,6 +26,7 @@ typedef struct tag_nt_usr_db_thread_data_t *nt_usr_db_thread_data_tp;
2626 typedef struct tag_nt_usr_db_thread_data_t{
2727 int read_count;
2828 wchar_t *dat_name;
29+ wchar_t *board_name;
2930 }nt_usr_db_thread_data_t;
3031
3132 extern void nt_usr_db_thread_data_free(void *ptr);
@@ -49,6 +50,8 @@ extern BOOL nt_usr_db_delete_thread_log(nt_usr_db_handle db_handle,
4950 nt_link_tp *thread_data_list);
5051 extern char* nt_usr_db_board_last_query(nt_usr_db_handle db_handle,
5152 const wchar_t *board_name);
53+extern nt_link_tp nt_usr_db_query_usr_table(nt_usr_db_handle db_handle,
54+ int offset, int limit);
5255
5356
5457 #endif /* __USR_DB_T_H_ */
--- a/src/inc/utils/nt_std_t.h
+++ b/src/inc/utils/nt_std_t.h
@@ -82,7 +82,8 @@ extern void nt_map_free(nt_map_handle handle, nt_memfree_fn value_free_func);
8282 extern BOOL nt_map_add_pair(nt_map_handle handle, const wchar_t *key, void *value);
8383 extern void* nt_map_find(nt_map_handle handle, const wchar_t *key);
8484 extern void* nt_map_remove(nt_map_handle handle, const wchar_t *key);
85-extern int nt_map_get_count(nt_enum_handle handle);
85+extern int nt_map_get_count(nt_map_handle handle);
86+extern nt_link_tp nt_map_get_values(nt_map_handle handle);
8687
8788 extern nt_queue_handle nt_queue_alloc();
8889 extern void nt_queue_free(nt_queue_handle h_que, nt_memfree_fn free_func);
@@ -120,6 +121,7 @@ extern int nt_link_num(nt_link_tp linkp);
120121 extern void* nt_link_get_by_index(nt_link_tp linkp, int index);
121122 extern void nt_all_link_free(nt_link_tp ptr, nt_memfree_fn free_func);
122123 extern nt_link_tp nt_link_copy(nt_link_tp src_linkp);
124+extern int nt_link_wcscmp_fnc(void *lhs, void *rhs);
123125
124126 typedef struct tag_nt_key_value_t *nt_key_value_tp;
125127 typedef struct tag_nt_key_value_t{
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,4 @@
1-/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
1+/* Copyright 2013,2014 Akira Ohta (akohta001@gmail.com)
22 This file is part of ntch.
33
44 The ntch is free software: you can redistribute it and/or modify
@@ -52,6 +52,8 @@
5252 #endif
5353 #define S_SIZE (1024)
5454
55+extern int server_main();
56+
5557 static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr);
5658 #ifdef NT_CLOUD
5759 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
@@ -92,6 +94,10 @@ int main(int argc, char *argv[])
9294 if(0 != set_option(argc, argv)){
9395 return 1;
9496 }
97+
98+ if(APP_MODE == NT_APP_MODE_SERVER){
99+ return server_main();
100+ }
95101
96102 sleep(1);
97103
@@ -279,6 +285,7 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
279285 nt_window_tp rwinp = NULL;
280286 nt_window_tp search_winp = NULL;
281287 nt_window_tp favorite_winp = NULL;
288+ nt_window_tp history_winp = NULL;
282289 char buf[256];
283290 wchar_t title_buf[128];
284291 wchar_t wch;
@@ -305,6 +312,8 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
305312 state = DISP_STATE_BOARDMENU;
306313 if(INIT_DISP_STATE == NT_INTI_DISP_FAVORITE){
307314 disp_state = DISP_STATE_FAVORITE;
315+ }else if(INIT_DISP_STATE == NT_INTI_DISP_HISTORY){
316+ disp_state = DISP_STATE_HISTORY;
308317 }else{
309318 disp_state = DISP_STATE_BOARDMENU;
310319 }
@@ -390,14 +399,9 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
390399 }else{
391400 print_error(scrp, NT_ERR_MSG_COUDLNOT_READ_BOARD);
392401 }
393- }else if(state == DISP_STATE_SEARCH_THREAD){
402+ }else if(state != DISP_STATE_BOARDMENU){
403+ disp_state = state;
394404 state = DISP_STATE_BOARDMENU;
395- disp_state = DISP_STATE_SEARCH_THREAD;
396- ch = NT_KEY_NONE;
397- continue;
398- }else if(DISP_STATE_FAVORITE == state){
399- state = DISP_STATE_BOARDMENU;
400- disp_state = DISP_STATE_FAVORITE;
401405 ch = NT_KEY_NONE;
402406 continue;
403407 }
@@ -433,6 +437,20 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
433437 }else{
434438 status_msg = NT_ERR_MSG_ADD_FAVORITE_FAILED;
435439 }
440+ }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
441+ if(nt_read_board(h_sel_items)){
442+ if(twinp->data){
443+ free_threadlist_ctx(twinp->data);
444+ twinp->data = NULL;
445+ }
446+ ch = NT_KEY_NONE;
447+ status_msg = NT_INFO_REFRESH_BOARD_SUCCESS;
448+ state = DISP_STATE_THREADTITLE;
449+ disp_state = state;
450+ continue;
451+ }else{
452+ status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD;
453+ }
436454 }
437455 state = DISP_STATE_THREADTITLE;
438456 ch = NT_KEY_NONE;
@@ -442,21 +460,6 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
442460 disp_state = state;
443461 ch = NT_KEY_NONE;
444462 continue;
445- }else if(DISP_STATE_REFRESH == state){
446- if(nt_read_board(h_sel_items)){
447- if(twinp->data){
448- free_threadlist_ctx(twinp->data);
449- twinp->data = NULL;
450- }
451- ch = NT_KEY_NONE;
452- status_msg = NT_INFO_REFRESH_BOARD_SUCCESS;
453- state = DISP_STATE_THREADTITLE;
454- disp_state = state;
455- continue;
456- }else{
457- status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD;
458- }
459- state = DISP_STATE_THREADTITLE;
460463 }else if(DISP_STATE_RESLIST == state){
461464 disp_state = state;
462465 if(!nt_read_thread(h_sel_items)){
@@ -478,14 +481,9 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
478481 state = DISP_STATE_THREADTITLE;
479482 ch = NT_KEY_NONE;
480483 continue;
481- }else if(DISP_STATE_SEARCH_THREAD == state){
482- state = DISP_STATE_THREADTITLE;
483- disp_state = DISP_STATE_SEARCH_THREAD;
484- ch = NT_KEY_NONE;
485- continue;
486- }else if(DISP_STATE_FAVORITE == state){
484+ }else if(DISP_STATE_THREADTITLE != state){
485+ disp_state = state;
487486 state = DISP_STATE_THREADTITLE;
488- disp_state = DISP_STATE_FAVORITE;
489487 ch = NT_KEY_NONE;
490488 continue;
491489 }else{
@@ -518,6 +516,21 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
518516 h_timer_auto_scroll, NT_AUTO_SCROLL_INTERVAL);
519517 }
520518 auto_scrolling = TRUE;
519+ }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
520+ state = DISP_STATE_RESLIST;
521+ ch = NT_KEY_NONE;
522+ if(!nt_read_thread(h_sel_items)){
523+ status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED;
524+ wclear(scrp);
525+ continue;
526+ }
527+ if(rwinp->data){
528+ free_reslist_ctx(rwinp->data);
529+ rwinp->data = NULL;
530+ }
531+ status_msg = NT_INFO_REFRESH_THREAD_SUCCESS;
532+ wclear(scrp);
533+ continue;
521534 }
522535 DISP_CLR_CMD(state);
523536 }
@@ -526,33 +539,9 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
526539 }
527540 if(DISP_STATE_ERROR == state){
528541 goto END_WHILE;
529- }else if(state == DISP_STATE_REFRESH){
530- state = DISP_STATE_RESLIST;
531- ch = NT_KEY_NONE;
532- if(!nt_read_thread(h_sel_items)){
533- status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED;
534- wclear(scrp);
535- continue;
536- }
537- if(rwinp->data){
538- free_reslist_ctx(rwinp->data);
539- rwinp->data = NULL;
540- }
541- status_msg = NT_INFO_REFRESH_THREAD_SUCCESS;
542- wclear(scrp);
543- continue;
544- }else if(state == DISP_STATE_SEARCH_THREAD){
545- state = DISP_STATE_RESLIST;
546- disp_state = DISP_STATE_SEARCH_THREAD;
547- ch = NT_KEY_NONE;
548- continue;
549- }else if(DISP_STATE_FAVORITE == state){
550- state = DISP_STATE_RESLIST;
551- disp_state = DISP_STATE_FAVORITE;
552- ch = NT_KEY_NONE;
553- continue;
554542 }else if(state != DISP_STATE_RESLIST){
555543 disp_state = state;
544+ state = DISP_STATE_RESLIST;
556545 ch = NT_KEY_NONE;
557546 continue;
558547 }
@@ -654,6 +643,62 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
654643 continue;
655644 }
656645 break;
646+ case DISP_STATE_HISTORY:
647+ draw_title(scrp, L"履歴", WA_REVERSE);
648+ if(!history_winp)
649+ history_winp = nt_disp_win_alloc(
650+ scrp, LINES-1, COLS, 1, 0, buf);
651+ if(!history_winp)
652+ goto END_WHILE;
653+ history_winp->key = ch;
654+ h_searched_thread = NULL;
655+ state = disp_history(history_winp, state, app_2ch_model,
656+ db_handle, &h_searched_thread, &linkp);
657+ if(linkp){
658+ nt_read_board_list(linkp);
659+ nt_all_link_free(linkp, _2ch_selected_item_free);
660+ }
661+ if(DISP_CMD(state)){
662+ ch = NT_KEY_NONE;
663+ if(DISP_CMD(state) == DISP_CMD_SEL_THREAD){
664+ assert(h_searched_thread);
665+ if(nt_set_sel_item(app_2ch_model,
666+ &h_sel_items_tmp, h_searched_thread, &status_msg)){
667+ nt_2ch_selected_item_release_ref(h_sel_items);
668+ h_sel_items = h_sel_items_tmp;
669+ if(rwinp->data){
670+ free_reslist_ctx(rwinp->data);
671+ rwinp->data = NULL;
672+ }
673+ if(twinp->data){
674+ free_threadlist_ctx(twinp->data);
675+ twinp->data = NULL;
676+ }
677+ }
678+ nt_searched_thread_release_ref(h_searched_thread);
679+ h_searched_thread = NULL;
680+ disp_state = DISP_STATE_RESLIST;
681+ state = DISP_STATE_HISTORY;
682+ DISP_CLR_CMD(state);
683+ continue;
684+ }else if(DISP_CMD(state) == DISP_CMD_REENTER){
685+ DISP_CLR_CMD(state);
686+ continue;
687+ }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
688+ DISP_CLR_CMD(state);
689+ if(history_winp->data){
690+ free_history_ctx(history_winp->data);
691+ history_winp->data = NULL;
692+ }
693+ continue;
694+ }
695+ }
696+ if(state != DISP_STATE_HISTORY){
697+ disp_state = state;
698+ ch = NT_KEY_NONE;
699+ continue;
700+ }
701+ break;
657702 case DISP_STATE_FAVORITE:
658703 draw_title(scrp, L"お気に入り", WA_REVERSE);
659704 if(!favorite_winp)
@@ -710,12 +755,12 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
710755 }else{
711756 status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
712757 }
713- }else if(DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD ||
714- DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_THREAD){
758+ }else if(DISP_CMD(state) == DISP_CMD_SEL_BOARD ||
759+ DISP_CMD(state) == DISP_CMD_SEL_THREAD){
715760 assert(h_searched_thread);
716761 if(nt_set_sel_item(app_2ch_model,
717762 &h_sel_items_tmp, h_searched_thread, &status_msg)){
718- disp_state = (DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD)
763+ disp_state = (DISP_CMD(state) == DISP_CMD_SEL_BOARD)
719764 ? DISP_STATE_THREADTITLE : DISP_STATE_RESLIST;
720765 state = DISP_STATE_FAVORITE;
721766 nt_2ch_selected_item_release_ref(h_sel_items);
@@ -731,6 +776,16 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
731776 }
732777 nt_searched_thread_release_ref(h_searched_thread);
733778 h_searched_thread = NULL;
779+ }else if(DISP_CMD(state) == DISP_CMD_REFRESH){
780+ state = DISP_STATE_FAVORITE;
781+ ch = NT_KEY_NONE;
782+ if(favorite_winp->data){
783+ free_favorite_ctx(favorite_winp->data);
784+ favorite_winp->data = NULL;
785+ }
786+ status_msg = NT_INFO_REFRESH_FAVORITE_SUCCESS;
787+ wclear(scrp);
788+ continue;
734789 #ifdef NT_CLOUD
735790 }else if(h_cloud){
736791 if(DISP_CMD(state) == DISP_CMD_UPLOAD_ALL ||
@@ -764,19 +819,10 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
764819 disp_state = state = DISP_STATE_FAVORITE;
765820 }
766821 continue;
767- }else if(state == DISP_STATE_REFRESH){
768- state = DISP_STATE_FAVORITE;
769- ch = NT_KEY_NONE;
770- if(favorite_winp->data){
771- free_favorite_ctx(favorite_winp->data);
772- favorite_winp->data = NULL;
773- }
774- status_msg = NT_INFO_REFRESH_FAVORITE_SUCCESS;
775- wclear(scrp);
776- continue;
777822 }else if(state != DISP_STATE_FAVORITE){
778823 ch = NT_KEY_NONE;
779824 disp_state = state;
825+ state = DISP_STATE_FAVORITE;
780826 continue;
781827 }else{
782828 disp_state = DISP_STATE_FAVORITE;
@@ -895,6 +941,11 @@ END_WHILE:
895941 free_board_menu_ctx(bwinp->data);
896942 free_threadlist_ctx(twinp->data);
897943 free_reslist_ctx(rwinp->data);
944+ if(history_winp){
945+ if(history_winp->data)
946+ free_history_ctx(history_winp->data);
947+ nt_disp_win_free(history_winp);
948+ }
898949 if(search_winp){
899950 if(search_winp->data)
900951 free_search_thread_ctx(search_winp->data);
--- a/src/net/nt_http.c
+++ b/src/net/nt_http.c
@@ -226,7 +226,7 @@ int nt_http_post2(const char *url, const char *post_data,
226226 }else if(IS_SET_FLAG(responsep, CHUNKED_FLAG)){
227227 p3 = p1 = out_buf;
228228 while(0 < (nread = strtol(p1, &p2, 16))){
229- memcpy(p3, p2+2, nread);
229+ memmove(p3, p2+2, nread);
230230 p3 += nread;
231231 p1 = p2 + nread + 4;
232232 }
--- a/src/net/nt_socket.c
+++ b/src/net/nt_socket.c
@@ -60,7 +60,6 @@ nt_socket_tp nt_socket_init(int port, char *addr)
6060 return NULL;
6161 }
6262
63- ptr->_sockaddr_in.sin_port = htons(port);
6463
6564 #ifdef NT_NET_IPV6
6665 memset(&addr_limit, 0, sizeof(addr_limit));
@@ -82,22 +81,27 @@ nt_socket_tp nt_socket_init(int port, char *addr)
8281 ptr->addr_family = AF_INET;
8382 s_addr = (struct sockaddr_in*)addr_list->ai_addr;
8483 ptr->_sockaddr_in.sin_family = AF_INET;
84+ ptr->_sockaddr_in.sin_port = htons(port);
8585 memcpy(&ptr->_sockaddr_in.sin_addr.s_addr,
8686 &s_addr->sin_addr.s_addr, sizeof(struct in_addr));
87+ freeaddrinfo(addr_out);
8788 return ptr;
8889 case AF_INET6:
8990 assert(addr_list->ai_addrlen == sizeof(struct sockaddr_in6));
9091 ptr->addr_family = AF_INET6;
9192 s_addr6 = (struct sockaddr_in6*)addr_list->ai_addr;
9293 ptr->_sockaddr_in6.sin6_family = AF_INET6;
94+ ptr->_sockaddr_in6.sin6_port = htons(port);
9395 memcpy(&ptr->_sockaddr_in6.sin6_addr.s6_addr,
9496 s_addr6->sin6_addr.s6_addr, sizeof(struct in6_addr));
97+ freeaddrinfo(addr_out);
9598 return ptr;
9699 }
97100 }
98101 freeaddrinfo(addr_out);
99102 #else
100103 ptr->_sockaddr_in.sin_family = AF_INET;
104+ ptr->_sockaddr_in.sin_port = htons(port);
101105 ptr->_sockaddr_in.sin_addr.s_addr = inet_addr(addr);
102106 if(ptr->_sockaddr_in.sin_addr.s_addr == 0xffffffff){
103107 hostinfo = gethostbyname(addr);
--- /dev/null
+++ b/src/server_main.c
@@ -0,0 +1,93 @@
1+/* Copyright 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 <signal.h>
23+#include <string.h>
24+#include <unistd.h>
25+#include <locale.h>
26+#include <iconv.h>
27+#include <netinet/in.h>
28+#include <assert.h>
29+
30+#include "env.h"
31+#include "error.h"
32+#include "nt_string.h"
33+#include "utils/nt_std_t.h"
34+#include "net/nt_http.h"
35+#include "net/nt_socket.h"
36+#include "net/nt_cookie.h"
37+#include "utils/file.h"
38+#include "usr/usr_db_t.h"
39+#include "utils/nt_mutex.h"
40+#include "utils/nt_pthread.h"
41+#include "utils/nt_timer.h"
42+#include "utils/base64.h"
43+#include "utils/crypt.h"
44+#include "usr/favorite_t.h"
45+#include "_2ch/_2ch.h"
46+#include "_2ch/maru_2ch.h"
47+#include "_2ch/search_2ch.h"
48+#include "ui/disp.h"
49+#include "ui/disp_win.h"
50+#include "ui/disp_string.h"
51+#ifdef NT_CLOUD
52+#include "cloud/nt_cloud.h"
53+#endif
54+
55+static BOOL DoLoop();
56+static BOOL do_loop;
57+static void interrupt_handler(int signal)
58+{
59+ do_loop = FALSE;
60+ fputs("Program recieved interrupt signal.\n", stderr);
61+}
62+
63+int server_main()
64+{
65+ int result;
66+ struct sigaction handler;
67+
68+ result = 1;
69+ do_loop = TRUE;
70+
71+ handler.sa_handler = interrupt_handler;
72+ if(sigfillset(&handler.sa_mask) < 0)
73+ return FALSE;
74+ handler.sa_flags = 0;
75+ if(sigaction(SIGINT, &handler, 0) < 0)
76+ return FALSE;
77+
78+ if(DoLoop())
79+ goto ERROR_TRAP;
80+
81+ result = 0;
82+ERROR_TRAP:
83+ return result;
84+}
85+
86+
87+static BOOL DoLoop()
88+{
89+ while(do_loop){
90+ sleep(1);
91+ }
92+ return TRUE;
93+}
--- a/src/ui/disp_board_menu.c
+++ b/src/ui/disp_board_menu.c
@@ -35,6 +35,7 @@
3535 #define NT_CMD_NONE 0
3636 #define NT_CMD_SEARCH_THREAD 1
3737 #define NT_CMD_FAVORITE 2
38+#define NT_CMD_HISTORY 3
3839
3940
4041 typedef struct tag_category_data_t *category_data_tp;
@@ -146,6 +147,8 @@ int disp_board_menu(nt_window_tp wp,
146147 return DISP_STATE_SEARCH_THREAD;
147148 case NT_CMD_FAVORITE:
148149 return DISP_STATE_FAVORITE;
150+ case NT_CMD_HISTORY:
151+ return DISP_STATE_HISTORY;
149152 }
150153 }
151154
@@ -494,6 +497,11 @@ static int parse_cmd1(const char *param)
494497 0 == strncmp(NT_COMMAND1_FAVORITE_2,param,
495498 strlen(NT_COMMAND1_FAVORITE_2))){
496499 return NT_CMD_FAVORITE;
500+ }else if(0 == strncmp(NT_COMMAND1_HISTORY_1,param,
501+ strlen(NT_COMMAND1_HISTORY_1)) ||
502+ 0 == strncmp(NT_COMMAND1_HISTORY_2,param,
503+ strlen(NT_COMMAND1_HISTORY_2))){
504+ return NT_CMD_HISTORY;
497505 }else{
498506 return NT_CMD_NONE;
499507 }
--- a/src/ui/disp_favorite.c
+++ b/src/ui/disp_favorite.c
@@ -36,7 +36,7 @@
3636 #define NT_CMD_UPLOAD_ALL 1
3737 #define NT_CMD_UPLOAD_BOARDS 2
3838 #define NT_CMD_UPLOAD_THREADS 3
39-
39+#define NT_CMD_DISP_HISTORY 4
4040
4141 typedef struct tag_favorite_ctx_t *favorite_ctx_tp;
4242 typedef struct tag_favorite_ctx_t {
@@ -110,7 +110,7 @@ int disp_favorite(nt_window_tp wp,
110110 }
111111 break;
112112 case NT_KEY_REFRESH:
113- return DISP_STATE_REFRESH;
113+ return DISP_CMD_REFRESH;
114114 case NT_KEY_COMMAND1:
115115 assert(wp->cmd_param);
116116 cmd = parse_cmd1(wp->cmd_param);
@@ -121,6 +121,8 @@ int disp_favorite(nt_window_tp wp,
121121 return DISP_CMD_UPLOAD_BOARDS;
122122 case NT_CMD_UPLOAD_THREADS:
123123 return DISP_CMD_UPLOAD_THREADS;
124+ case NT_CMD_DISP_HISTORY:
125+ return DISP_STATE_HISTORY;
124126 }
125127 break;
126128 case NT_KEY_CLOSE:
@@ -212,7 +214,7 @@ int disp_favorite(nt_window_tp wp,
212214 (*h_sel_threadp) = nt_searched_thread_alloc(
213215 board_name, NULL, NULL);
214216 if((*h_sel_threadp))
215- result_state |= DISP_CMD_SEL_FAVORITE_BOARD;
217+ result_state |= DISP_CMD_SEL_BOARD;
216218 }
217219 }else{
218220 attr = 0;
@@ -265,12 +267,12 @@ int disp_favorite(nt_window_tp wp,
265267 (*h_sel_threadp) = nt_searched_thread_alloc(
266268 board_name, dat_name, title);
267269 if((*h_sel_threadp))
268- result_state |= DISP_CMD_SEL_FAVORITE_THREAD;
270+ result_state |= DISP_CMD_SEL_THREAD;
269271 }else if(sel_flag2){
270272 (*h_sel_threadp) = nt_searched_thread_alloc(
271273 board_name, NULL, NULL);
272274 if((*h_sel_threadp))
273- result_state |= DISP_CMD_SEL_FAVORITE_BOARD;
275+ result_state |= DISP_CMD_SEL_BOARD;
274276 }
275277 }else{
276278 attr = 0;
@@ -468,6 +470,11 @@ static int parse_cmd1(const char *param)
468470 if(0 == strncmp(NT_COMMAND1_UPLOAD_1,param,
469471 strlen(NT_COMMAND1_UPLOAD_1))){
470472 offset = strlen(NT_COMMAND1_UPLOAD_1);
473+ }else if((0 == strncmp(NT_COMMAND1_HISTORY_1,param,
474+ strlen(NT_COMMAND1_HISTORY_1))) ||
475+ (0 == strncmp(NT_COMMAND1_HISTORY_2,param,
476+ strlen(NT_COMMAND1_HISTORY_2)))){
477+ return NT_CMD_DISP_HISTORY;
471478 }else{
472479 return NT_CMD_NONE;
473480 }
@@ -485,6 +492,7 @@ static int parse_cmd1(const char *param)
485492 0 == strncmp(start, NT_COMMAND1_UPLOAD_THREAD2,len)){
486493 return NT_CMD_UPLOAD_THREADS;
487494 }
495+
488496 return NT_CMD_ERR;
489497 }
490498
--- /dev/null
+++ b/src/ui/disp_history.c
@@ -0,0 +1,573 @@
1+/* Copyright 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 <stdlib.h>
19+#include <stdio.h>
20+#include <string.h>
21+#include <assert.h>
22+#include <wchar.h>
23+
24+#include "env.h"
25+#include "nt_string.h"
26+#include "utils/nt_std_t.h"
27+#include "utils/text.h"
28+#include "_2ch/model_2ch.h"
29+#include "_2ch/search_2ch.h"
30+#include "ui/disp.h"
31+#include "ui/disp_string.h"
32+#include "usr/usr_db_t.h"
33+
34+#define NT_CMD_ERR -1
35+#define NT_CMD_NONE 0
36+#define NT_CMD_LIMIT 1
37+
38+#define LINE_HEIGHT 2
39+
40+typedef struct tag_history_ctx_t *history_ctx_tp;
41+typedef struct tag_history_ctx_t {
42+ int prev_state;
43+ int cur_cursor;
44+ int scroll_pos;
45+ int query_offset;
46+ int query_limit;
47+ BOOL update_query;
48+ nt_enum_handle h_enum_disp_data;
49+}history_ctx_t;
50+
51+typedef struct tag_disp_data_t *disp_data_tp;
52+typedef struct tag_disp_data_t{
53+ wchar_t *board_name;
54+ wchar_t *dat_name;
55+ wchar_t *title;
56+ int read_count;
57+ int res_count;
58+}disp_data_t;
59+
60+static history_ctx_tp init_context();
61+static disp_data_tp disp_data_alloc(
62+ const wchar_t *board_name,
63+ const wchar_t *dat_name, int read_count);
64+static void disp_data_free(void *ptr);
65+static BOOL set_model_data(nt_2ch_model_handle h_model,
66+ nt_enum_handle h_enum_disp_data,
67+ nt_link_tp *update_board_list);
68+
69+
70+static int adjust_scroll_pos(nt_window_tp wp,
71+ history_ctx_tp ctxp);
72+static int parse_cmd1(const char *param, int *limit, int *offset);
73+
74+
75+static BOOL set_model_data(nt_2ch_model_handle h_model,
76+ nt_enum_handle h_enum_disp_data,
77+ nt_link_tp *update_board_list)
78+{
79+ nt_mutex_handle h_mutex;
80+ disp_data_tp disp_datap;
81+ nt_category_handle h_category;
82+ nt_board_handle h_board;
83+ nt_thread_handle h_thread;
84+ wchar_t *title;
85+ wchar_t *wc;
86+ nt_map_handle h_map;
87+ nt_2ch_selected_item_handle h_select;
88+
89+ assert(h_model);
90+ assert(h_enum_disp_data);
91+
92+ if(update_board_list)
93+ *update_board_list = NULL;
94+
95+ h_map = NULL;
96+
97+ h_mutex = nt_2ch_model_get_mutex(h_model);
98+ if(!h_mutex)
99+ return FALSE;
100+ if(!nt_mutex_lock(h_mutex)){
101+ return FALSE;
102+ }
103+ nt_enum_reset(h_enum_disp_data);
104+ while(NULL != (disp_datap =
105+ (disp_data_tp)nt_enum_fetch(h_enum_disp_data))){
106+ if(disp_datap->title)
107+ continue;
108+ h_thread = nt_get_thread_by_board_and_dat_name(
109+ h_model, disp_datap->board_name, disp_datap->dat_name);
110+ title = NULL;
111+ if(h_thread){
112+ title = nt_w_trim(nt_thread_get_title(h_thread));
113+ }
114+ if(!title){
115+ h_board = nt_get_board_by_name(h_model,
116+ disp_datap->board_name, &h_category);
117+ if(!h_board){
118+ if(h_thread)
119+ nt_thread_release_ref(h_thread);
120+ continue;
121+ }
122+
123+ wc = nt_read_thread_title(
124+ h_board, disp_datap->dat_name);
125+ if(!wc){
126+ if(h_thread){
127+ /* Not in subject.txt */
128+ nt_board_release_ref(h_board);
129+ nt_category_release_ref(h_category);
130+ nt_thread_release_ref(h_thread);
131+ }else if(update_board_list){
132+ /* May contain subject.txt but yet to be downloaded. */
133+ if(!h_map){
134+ h_map = nt_map_alloc();
135+ if(!h_map){
136+ nt_board_release_ref(h_board);
137+ nt_category_release_ref(h_category);
138+ continue;
139+ }
140+ }else if(nt_map_find(h_map, disp_datap->board_name)){
141+ nt_board_release_ref(h_board);
142+ nt_category_release_ref(h_category);
143+ continue;
144+ }
145+ h_select = nt_2ch_selected_item_alloc();
146+ if(h_select){
147+ nt_set_selected_board(h_select, h_category, h_board);
148+ nt_board_release_ref(h_board);
149+ nt_category_release_ref(h_category);
150+ if(!nt_map_add_pair(h_map, disp_datap->board_name, h_select)){
151+ nt_2ch_selected_item_release_ref(h_select);
152+ }
153+ }else{
154+ nt_board_release_ref(h_board);
155+ nt_category_release_ref(h_category);
156+ }
157+ }else{
158+ nt_board_release_ref(h_board);
159+ nt_category_release_ref(h_category);
160+ }
161+ continue;
162+ }
163+ nt_board_release_ref(h_board);
164+ nt_category_release_ref(h_category);
165+ title = nt_w_trim(wc);
166+ free(wc);
167+ }
168+ if(h_thread){
169+ disp_datap->res_count = nt_thread_get_res_count(h_thread);
170+ nt_thread_release_ref(h_thread);
171+ }
172+ if(disp_datap->res_count < 0)
173+ disp_datap->res_count = 0;
174+ if(title){
175+ disp_datap->title = title;
176+ }
177+ }
178+
179+ if(!nt_mutex_unlock(h_mutex)){
180+ assert(0);
181+ }
182+ if(h_map)
183+ *update_board_list = nt_map_get_values(h_map);
184+ return TRUE;
185+}
186+
187+
188+static history_ctx_tp init_context()
189+{
190+ history_ctx_tp ctxp;
191+
192+ ctxp = malloc(sizeof(history_ctx_t));
193+ if(!ctxp)
194+ return NULL;
195+
196+ ctxp->prev_state = DISP_STATE_HISTORY;
197+ ctxp->cur_cursor = 0;
198+ ctxp->scroll_pos = 0;
199+ ctxp->query_offset = 0;
200+ ctxp->query_limit = 100;
201+ ctxp->update_query = FALSE;
202+ ctxp->h_enum_disp_data = NULL;
203+
204+ return ctxp;
205+}
206+
207+void free_history_ctx(void *ptr)
208+{
209+ history_ctx_tp ctxp;
210+
211+ assert(ptr);
212+
213+ ctxp = (history_ctx_tp)ptr;
214+ if(ctxp->h_enum_disp_data){
215+ nt_enum_set_free_func(ctxp->h_enum_disp_data, disp_data_free);
216+ nt_enum_unset(ctxp->h_enum_disp_data);
217+ }
218+ free(ctxp);
219+}
220+
221+
222+static nt_link_tp set_disp_data(nt_link_tp slinkp)
223+{
224+ nt_link_tp rlinkp, wlinkp, dlinkp;
225+ disp_data_tp datap;
226+ nt_usr_db_thread_data_tp db_datap;
227+
228+ if(!slinkp)
229+ return NULL;
230+
231+ rlinkp = NULL;
232+ wlinkp = slinkp;
233+ do{
234+ db_datap = (nt_usr_db_thread_data_tp)wlinkp->data;
235+ datap = disp_data_alloc(
236+ db_datap->board_name,
237+ db_datap->dat_name,
238+ db_datap->read_count);
239+
240+ if(datap){
241+ dlinkp = nt_link_add_data(rlinkp, datap);
242+ if(!rlinkp)
243+ rlinkp = dlinkp;
244+ }
245+ wlinkp = wlinkp->next;
246+ }while(wlinkp != slinkp);
247+
248+ return rlinkp;
249+}
250+
251+int disp_history(nt_window_tp wp,
252+ int prev_state, nt_2ch_model_handle h_model,
253+ nt_usr_db_handle h_usr_db,
254+ nt_searched_thread_handle *h_sel_threadp,
255+ nt_link_tp *update_board_list)
256+{
257+ int result_state;
258+ history_ctx_tp ctxp;
259+ nt_link_tp linkp, data_linkp;
260+ disp_data_tp disp_datap;
261+ int row, num, limit_row, nwrite, len;
262+ int limit, offset, cmd;
263+ attr_t attr;
264+ BOOL b_result;
265+ const wchar_t *title;
266+ wchar_t wbuf[256];
267+ wchar_t wbuf2[32];
268+ int read_count, res_count;
269+
270+
271+ result_state = DISP_STATE_HISTORY;
272+ *update_board_list = NULL;
273+
274+ ctxp = (history_ctx_tp)wp->data;
275+ if(!ctxp){
276+ ctxp = init_context();
277+ if(!ctxp)
278+ return DISP_STATE_ERROR;
279+
280+ wp->data = ctxp;
281+ }
282+
283+ if(prev_state != DISP_STATE_HISTORY || ctxp->update_query){
284+ if(prev_state != DISP_STATE_HISTORY)
285+ ctxp->prev_state = prev_state;
286+ ctxp->update_query = FALSE;
287+ linkp = nt_usr_db_query_usr_table(h_usr_db,
288+ ctxp->query_offset,
289+ ctxp->query_limit);
290+ if(linkp){
291+ if(ctxp->h_enum_disp_data){
292+ nt_enum_set_free_func(ctxp->h_enum_disp_data, disp_data_free);
293+ nt_enum_unset(ctxp->h_enum_disp_data);
294+ }
295+ data_linkp = set_disp_data(linkp);
296+ ctxp->h_enum_disp_data = nt_enum_set(data_linkp);
297+ if(!ctxp->h_enum_disp_data){
298+ free_history_ctx(ctxp);
299+ return DISP_STATE_ERROR;
300+ }
301+ b_result = set_model_data(h_model,
302+ ctxp->h_enum_disp_data, update_board_list);
303+ nt_all_link_free(linkp, nt_usr_db_thread_data_free);
304+ if(!b_result){
305+ free_history_ctx(ctxp);
306+ return DISP_STATE_ERROR;
307+ }
308+ }
309+ }
310+
311+ switch(wp->key){
312+ case NT_KEY_CMD_BOARD_UPDATE:
313+ if(ctxp->h_enum_disp_data){
314+ set_model_data(h_model, ctxp->h_enum_disp_data, NULL);
315+ }
316+ break;
317+ case NT_KEY_CLOSE:
318+ case KEY_LEFT:
319+ return DISP_STATE_BOARDMENU;
320+ case NT_KEY_REFRESH:
321+ return DISP_CMD_REFRESH;
322+ case NT_KEY_COMMAND1:
323+ assert(wp->cmd_param);
324+ cmd = parse_cmd1(wp->cmd_param, &limit, &offset);
325+ switch(cmd){
326+ case NT_CMD_LIMIT:
327+ if(limit >= 0)
328+ ctxp->query_limit = limit;
329+ if(offset >= 0)
330+ ctxp->query_offset = offset;
331+ if(limit < 0 && offset < 0){
332+ ctxp->query_offset += ctxp->query_limit;
333+ }
334+ ctxp->update_query = TRUE;
335+ ctxp->cur_cursor = 0;
336+ ctxp->scroll_pos = 0;
337+ return (DISP_STATE_RESLIST | DISP_CMD_REENTER);
338+ }
339+ break;
340+ case NT_KEY_RIGHT:
341+ return ctxp->prev_state;
342+ case NT_KEY_SELECT:
343+ case KEY_RIGHT:
344+ num = 0;
345+ nt_enum_reset(ctxp->h_enum_disp_data);
346+ while(NULL !=
347+ (disp_datap = (disp_data_tp)
348+ nt_enum_fetch(ctxp->h_enum_disp_data))){
349+ if(ctxp->cur_cursor != num++)
350+ continue;
351+ assert(disp_datap->board_name);
352+ assert(disp_datap->dat_name);
353+ (*h_sel_threadp) = nt_searched_thread_alloc(
354+ disp_datap->board_name,
355+ disp_datap->dat_name,
356+ disp_datap->title);
357+ if(*h_sel_threadp){
358+ return (DISP_STATE_RESLIST | DISP_CMD_SEL_THREAD);
359+ }
360+ }
361+ break;
362+ case NT_KEY_UP:
363+ case KEY_UP:
364+ ctxp->cur_cursor--;
365+ adjust_scroll_pos(wp, ctxp);
366+ break;
367+ case NT_KEY_DOWN:
368+ case KEY_DOWN:
369+ ctxp->cur_cursor++;
370+ adjust_scroll_pos(wp, ctxp);
371+ break;
372+ case NT_KEY_PAGEUP:
373+ case KEY_PPAGE:
374+ ctxp->cur_cursor -= wp->lines / LINE_HEIGHT;
375+ adjust_scroll_pos(wp, ctxp);
376+ break;
377+ case NT_KEY_PAGEDOWN:
378+ case KEY_NPAGE:
379+ ctxp->cur_cursor += wp->lines / LINE_HEIGHT;
380+ adjust_scroll_pos(wp, ctxp);
381+ break;
382+ }
383+
384+ nt_enum_reset(ctxp->h_enum_disp_data);
385+
386+ row = 0;
387+ num = 0;
388+ limit_row = ctxp->scroll_pos + wp->lines;
389+ while(NULL !=
390+ (disp_datap = (disp_data_tp)
391+ nt_enum_fetch(ctxp->h_enum_disp_data))){
392+ nwrite = -1;
393+ attr = (ctxp->cur_cursor == num) ? WA_BOLD : 0;
394+ num++;
395+ read_count = disp_datap->read_count;
396+ res_count = disp_datap->res_count;
397+ if(res_count == 0)
398+ res_count = read_count;
399+ title = disp_datap->title;
400+ if(!title)
401+ title = L"Unknown Title";
402+ swprintf(wbuf, sizeof(wbuf), L"%3d [%ls] %ls (%d)", num + ctxp->query_offset,
403+ disp_datap->board_name, title, res_count);
404+ if(read_count < res_count){
405+ swprintf(wbuf2, sizeof(wbuf2), L"未読%d", res_count - read_count);
406+ wcscat(wbuf, wbuf2);
407+ }
408+ if(row >= ctxp->scroll_pos){
409+ wmove(wp->wp, row - ctxp->scroll_pos, 0);
410+ nwrite = nt_add_wnstr(wp->wp, wbuf, attr, wp->cols);
411+ }else{
412+ nwrite = nt_get_wc_count_within_colmns(wbuf, wp->cols);
413+ }
414+ if(limit_row <= ++row)
415+ break;
416+
417+ attr |= WA_UNDERLINE;
418+ if(row >= ctxp->scroll_pos){
419+ if(wcslen(wbuf+nwrite) > 0){
420+ len = nt_get_column_length(wbuf+nwrite);
421+ wmove(wp->wp, row - ctxp->scroll_pos, 0);
422+ nt_add_wnch(wp->wp, L' ', attr, 3);
423+ nt_add_wstr(wp->wp, wbuf+nwrite, attr);
424+ if(0 < (wp->cols - len))
425+ nt_add_wnch(wp->wp, L' ', attr, wp->cols - len);
426+ }else{
427+ wmove(wp->wp, row - ctxp->scroll_pos, 0);
428+ nt_add_wnch(wp->wp, L' ', attr, wp->cols);
429+ }
430+ }
431+ if(limit_row <= ++row)
432+ break;
433+ }
434+
435+ return result_state;
436+}
437+
438+
439+static int adjust_scroll_pos(nt_window_tp wp,
440+ history_ctx_tp ctxp)
441+{
442+ int num_data;
443+ int cursor_pos;
444+ int max_viaible_row;
445+
446+ num_data = nt_enum_get_count(ctxp->h_enum_disp_data);
447+ if(num_data <= ctxp->cur_cursor){
448+ ctxp->cur_cursor = num_data - 1;
449+ }
450+
451+ if(ctxp->cur_cursor <= 0){
452+ ctxp->cur_cursor = 0;
453+ ctxp->scroll_pos = 0;
454+ return 0;
455+ }
456+
457+ cursor_pos = ctxp->cur_cursor * LINE_HEIGHT;
458+
459+ if(cursor_pos < ctxp->scroll_pos){
460+ ctxp->scroll_pos = cursor_pos;
461+ return cursor_pos;
462+ }
463+
464+ max_viaible_row = ctxp->scroll_pos + wp->lines - LINE_HEIGHT;
465+ if(max_viaible_row >= cursor_pos){
466+ return cursor_pos;
467+ }
468+
469+ ctxp->scroll_pos = cursor_pos - wp->lines + LINE_HEIGHT;
470+
471+ return cursor_pos;
472+}
473+
474+
475+static disp_data_tp disp_data_alloc(
476+ const wchar_t *board_name,
477+ const wchar_t *dat_name, int read_count)
478+{
479+ disp_data_tp datap;
480+
481+ if(read_count <= 0)
482+ return NULL;
483+ datap = malloc(sizeof(disp_data_t));
484+ if(!datap)
485+ return NULL;
486+
487+ datap->board_name = nt_w_str_clone(board_name);
488+ if(!datap->board_name){
489+ free(datap);
490+ return NULL;
491+ }
492+ datap->dat_name = nt_w_str_clone(dat_name);
493+ if(!datap->dat_name){
494+ free(datap->board_name);
495+ free(datap);
496+ return NULL;
497+ }
498+ datap->title = NULL;
499+ datap->read_count = read_count;
500+ datap->res_count = 0;
501+
502+ return datap;
503+}
504+
505+static void disp_data_free(void *ptr)
506+{
507+ disp_data_tp datap;
508+ assert(ptr);
509+ datap = (disp_data_tp)ptr;
510+
511+ if(datap->title)
512+ free(datap->title);
513+ free(datap->board_name);
514+ free(datap->dat_name);
515+ free(datap);
516+}
517+
518+static int parse_cmd1(const char *param, int *limit, int *offset)
519+{
520+ int len, i, state;
521+ const char *start, *end;
522+ char c;
523+
524+ assert(param);
525+
526+ if(!nt_strtok(param, ' ', &start, &end))
527+ return NT_CMD_NONE;
528+
529+ len = end - start;
530+ if(len <= 0)
531+ return NT_CMD_NONE;
532+
533+ if(0 == strncmp(NT_COMMAND1_LIMIT_1, start, len) ||
534+ 0 == strncmp(NT_COMMAND1_LIMIT_2, start, len)){
535+ }else{
536+ return NT_CMD_NONE;
537+ }
538+
539+ *limit = -1;
540+ *offset = -1;
541+
542+ if(!nt_strtok(end, ' ', &start, &end))
543+ return NT_CMD_LIMIT;
544+
545+ *limit = 0;
546+ state = 0;
547+ len = strlen(start);
548+ for(i = 0; i < len; i++){
549+ c = start[i];
550+ if(c >= '0' && c <= '9'){
551+ *limit *= 10;
552+ *limit += c - '0';
553+ }else if(c == ','){
554+ if(state == 0){
555+ state = 1;
556+ *offset = *limit;
557+ *limit = 0;
558+ }else{
559+ return NT_CMD_ERR;
560+ }
561+ }else if(c != ' '){
562+ break;
563+ }
564+ }
565+ if(*limit == 0){
566+ *limit = -1;
567+ }
568+ return NT_CMD_LIMIT;
569+}
570+
571+
572+
573+
--- a/src/ui/disp_reslist.c
+++ b/src/ui/disp_reslist.c
@@ -41,7 +41,8 @@
4141 #define NT_CMD_ID 4
4242 #define NT_CMD_SEARCH_THREAD 5
4343 #define NT_CMD_FAVORITE 6
44-#define NT_CMD_AUTO_SCROLL 7
44+#define NT_CMD_HISTORY 7
45+#define NT_CMD_AUTO_SCROLL 8
4546
4647 #define AUTO_SCROLL_NONE 0
4748 #define AUTO_SCROLL_UP -1
@@ -241,7 +242,9 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
241242 }
242243 break;
243244 case NT_KEY_REFRESH:
244- return DISP_STATE_REFRESH;
245+ return DISP_CMD_REFRESH;
246+ case NT_KEY_ERASE:
247+ return DISP_STATE_THREADTITLE;
245248 case NT_KEY_CLOSE:
246249 case KEY_LEFT:
247250 return ctxp->prev_state;
@@ -430,6 +433,8 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
430433 return DISP_STATE_SEARCH_THREAD;
431434 case NT_CMD_FAVORITE:
432435 return DISP_STATE_FAVORITE;
436+ case NT_CMD_HISTORY:
437+ return DISP_STATE_HISTORY;
433438 case NT_CMD_WRITE:
434439 return DISP_STATE_EDITOR;
435440 case NT_CMD_JMP_NEW:
@@ -920,6 +925,11 @@ static int parse_cmd1(const char *param, const char **end)
920925 0 == strncmp(NT_COMMAND1_FAVORITE_2,param,
921926 strlen(NT_COMMAND1_FAVORITE_2))){
922927 return NT_CMD_FAVORITE;
928+ }else if(0 == strncmp(NT_COMMAND1_HISTORY_1,param,
929+ strlen(NT_COMMAND1_HISTORY_1)) ||
930+ 0 == strncmp(NT_COMMAND1_HISTORY_2,param,
931+ strlen(NT_COMMAND1_HISTORY_2))){
932+ return NT_CMD_HISTORY;
923933 }else if(0 == strncmp(NT_COMMAND1_AUTOSCROLL_1,param,
924934 strlen(NT_COMMAND1_AUTOSCROLL_1)) ||
925935 0 == strncmp(NT_COMMAND1_AUTOSCROLL_2,param,
@@ -939,7 +949,8 @@ static ctx_reslist_tp init_context(nt_2ch_selected_item_handle h_select,
939949
940950 board_name = nt_2ch_selected_item_get_board_name(h_select);
941951 dat_name = nt_2ch_selected_item_get_thread_dat_name(h_select);
942- assert(board_name && dat_name);
952+ assert(board_name);
953+ assert(dat_name);
943954
944955 ctxp = (ctx_reslist_tp)calloc(1,sizeof(ctx_reslist_t));
945956
--- a/src/ui/disp_threadlist.c
+++ b/src/ui/disp_threadlist.c
@@ -78,6 +78,7 @@ static BOOL get_thread_data_by_dat_name(const wchar_t *dat_name, nt_link_tp disp
7878 #define NT_CMD_DEL_THREAD_LOG 4
7979 #define NT_CMD_SEARCH_THREAD 5
8080 #define NT_CMD_FAVORITE 6
81+#define NT_CMD_HISTORY 7
8182
8283 static int parse_cmd1(const char *param);
8384 static thread_disp_data_tp get_thread_by_seq_no(nt_link_tp linkp, int seq_no);
@@ -183,8 +184,10 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
183184
184185 switch(ch){
185186 case NT_KEY_REFRESH:
186- result_state = DISP_STATE_REFRESH;
187+ result_state = DISP_CMD_REFRESH;
187188 goto ERROR_TRAP;
189+ case NT_KEY_ERASE:
190+ return DISP_STATE_BOARDMENU;
188191 case NT_KEY_CLOSE:
189192 case KEY_LEFT:
190193 result_state = ctxp->prev_state;
@@ -242,17 +245,17 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
242245 case NT_CMD_SORT_NUMBER:
243246 THREAD_SORT_TYPE = NT_THREAD_SORT_BY_NUMBER;
244247 sort_thread_title(THREAD_SORT_TYPE, ctxp);
245- result_state = DISP_STATE_REFRESH;
248+ result_state = DISP_CMD_REFRESH;
246249 goto ERROR_TRAP;
247250 case NT_CMD_SORT_READ:
248251 THREAD_SORT_TYPE = NT_THREAD_SORT_BY_READ;
249252 sort_thread_title(THREAD_SORT_TYPE, ctxp);
250- result_state = DISP_STATE_REFRESH;
253+ result_state = DISP_CMD_REFRESH;
251254 goto ERROR_TRAP;
252255 case NT_CMD_SORT_UNREAD:
253256 THREAD_SORT_TYPE = NT_THREAD_SORT_BY_UNREAD;
254257 sort_thread_title(THREAD_SORT_TYPE, ctxp);
255- result_state = DISP_STATE_REFRESH;
258+ result_state = DISP_CMD_REFRESH;
256259 goto ERROR_TRAP;
257260 case NT_CMD_DEL_THREAD_LOG:
258261 if(!nt_strtok(wp->cmd_param,' ', &start, &end))
@@ -274,7 +277,7 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
274277 }
275278 nt_cloud_release_ref(h_cloud);
276279 }
277- result_state = DISP_STATE_REFRESH;
280+ result_state = DISP_CMD_REFRESH;
278281 goto ERROR_TRAP;
279282 }
280283 linkp = nt_parse_number_list(cptr, NULL);
@@ -306,7 +309,7 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
306309 if(h_cloud)
307310 nt_cloud_release_ref(h_cloud);
308311 nt_all_link_free(linkp, NULL);
309- result_state = DISP_STATE_REFRESH;
312+ result_state = DISP_CMD_REFRESH;
310313 goto ERROR_TRAP;
311314 case NT_CMD_SEARCH_THREAD:
312315 result_state = DISP_STATE_SEARCH_THREAD;
@@ -314,6 +317,9 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
314317 case NT_CMD_FAVORITE:
315318 result_state = DISP_STATE_FAVORITE;
316319 goto ERROR_TRAP;
320+ case NT_CMD_HISTORY:
321+ result_state = DISP_STATE_HISTORY;
322+ goto ERROR_TRAP;
317323 default:
318324 break;
319325 }
@@ -854,6 +860,11 @@ static int parse_cmd1(const char *param)
854860 0 == strncmp(NT_COMMAND1_FAVORITE_2,param,
855861 strlen(NT_COMMAND1_FAVORITE_2))){
856862 return NT_CMD_FAVORITE;
863+ }else if(0 == strncmp(NT_COMMAND1_HISTORY_1,param,
864+ strlen(NT_COMMAND1_HISTORY_1)) ||
865+ 0 == strncmp(NT_COMMAND1_HISTORY_2,param,
866+ strlen(NT_COMMAND1_HISTORY_2))){
867+ return NT_CMD_HISTORY;
857868 }else if(0 == strncmp(NT_COMMAND1_SORT_1, param,
858869 strlen(NT_COMMAND1_SORT_1))){
859870 offset = strlen(NT_COMMAND1_SORT_1);
--- a/src/usr/favorite_t.c
+++ b/src/usr/favorite_t.c
@@ -77,10 +77,6 @@ typedef struct tag_nt_favorite_thread_t {
7777 int num_res;
7878 } nt_favorite_thread_t;
7979
80-static int local_wcscmp(void *lhs, void *rhs)
81-{
82- return wcscmp((const wchar_t *)lhs, (const wchar_t *)rhs);
83-}
8480 static void free_favorite_board(void *ptr);
8581 static void free_favorite_grp(void *ptr);
8682 static void free_grp_content(void *ptr);
@@ -1377,7 +1373,7 @@ nt_link_tp nt_favorite_get_update_board_list(
13771373 continue;
13781374 if(board_name_linkp){
13791375 cptr = (const wchar_t*)nt_link_find(
1380- board_name_linkp, (void*)board_name, local_wcscmp);
1376+ board_name_linkp, (void*)board_name, nt_link_wcscmp_fnc);
13811377 if(cptr)
13821378 continue;
13831379 }
--- a/src/usr/usr_db_t.c
+++ b/src/usr/usr_db_t.c
@@ -84,12 +84,17 @@ static const char *NT_SQL_QUERY_BOARD_LAST_QUERY =
8484 "SELECT date_time FROM usr_log WHERE rec_type = 1 "
8585 "AND board_name = :board_name AND dat_name = 'query_time' ";
8686
87+static const char *NT_SQL_QUERY_USR_TABLE =
88+ "SELECT board_name, dat_name, res_no FROM usr_log "
89+ "ORDER BY date_time DESC "
90+ "LIMIT :limit OFFSET :offset ";
8791
8892 static BOOL usr_tbl_create(sqlite3 *dbp);
8993 static int usr_tbl_validate(sqlite3 *dbp);
9094
9195 static nt_usr_db_thread_data_tp
92- thread_data_alloc(int read_count, const wchar_t *dat_name);
96+ thread_data_alloc(int read_count,
97+ const wchar_t *dat_name, const wchar_t *board_name);
9398 static BOOL nt_remove_thread_data(nt_link_tp *thread_data,
9499 const wchar_t *dat_name);
95100
@@ -271,7 +276,7 @@ nt_link_tp nt_usr_db_query_read_count_list(nt_usr_db_handle db_handle,
271276 dat_nm_buf, sizeof(dat_nm_buf)))
272277 goto ERROR_TRAP;
273278 thread_datap =
274- thread_data_alloc(res_no, dat_nm_buf);
279+ thread_data_alloc(res_no, dat_nm_buf, NULL);
275280 if(!thread_datap)
276281 goto ERROR_TRAP;
277282 linkp = nt_link_add_data(result_linkp, thread_datap);
@@ -612,6 +617,110 @@ ERROR_TRAP:
612617 return result;
613618 }
614619
620+nt_link_tp nt_usr_db_query_usr_table(nt_usr_db_handle db_handle,
621+ int offset, int limit)
622+{
623+ nt_link_tp result_linkp;
624+ nt_link_tp linkp;
625+ nt_usr_db_thread_data_tp thread_datap;
626+ const unsigned char *dat_name, *board_name;
627+ int res_no;
628+ int rc , idx;
629+ ctx_usr_db_tp ctxp;
630+ wchar_t board_nm_buf[128];
631+ wchar_t dat_nm_buf[64];
632+ sqlite3_stmt *stmt;
633+ iconv_t icd;
634+ BOOL result;
635+
636+ assert(db_handle);
637+ assert(db_handle->chk_sum == NT_USR_DB_CHK_SUM);
638+
639+ result_linkp = NULL;
640+ stmt = NULL;
641+ icd = (iconv_t)-1;
642+ result = FALSE;
643+
644+ ctxp = (ctx_usr_db_tp)db_handle;
645+
646+ if(!nt_usr_db_open(db_handle)){
647+ return NULL;
648+ }
649+
650+ rc = sqlite3_prepare_v2(ctxp->dbp,
651+ NT_SQL_QUERY_USR_TABLE, -1,
652+ &stmt, NULL);
653+ if(rc != SQLITE_OK){
654+ fputs(sqlite3_errmsg(ctxp->dbp), stderr);
655+ nt_usr_db_close(db_handle);
656+ return NULL;
657+ }
658+ idx = sqlite3_bind_parameter_index(stmt, ":limit");
659+ if(idx == 0 ||
660+ SQLITE_OK != sqlite3_bind_int(stmt, idx, limit)){
661+ goto ERROR_TRAP;
662+ }
663+ idx = sqlite3_bind_parameter_index(stmt, ":offset");
664+ if(idx == 0 ||
665+ SQLITE_OK != sqlite3_bind_int(stmt, idx, offset)){
666+ goto ERROR_TRAP;
667+ }
668+
669+ icd = iconv_open("wchar_t", "UTF-8");
670+ if(icd == (iconv_t)-1){
671+ perror("e");
672+ goto ERROR_TRAP;
673+ }
674+
675+ while(SQLITE_ROW == (rc = sqlite3_step(stmt))){
676+ res_no = sqlite3_column_int(stmt, 2);
677+ if(res_no <= 0)
678+ continue;
679+ dat_name = sqlite3_column_text(stmt, 1);
680+ if(dat_name == NULL)
681+ goto ERROR_TRAP;
682+ board_name = sqlite3_column_text(stmt, 0);
683+ if(board_name == NULL)
684+ goto ERROR_TRAP;
685+
686+ if(!nt_conv_local2wc(icd, (char*)dat_name,
687+ dat_nm_buf, sizeof(dat_nm_buf)))
688+ goto ERROR_TRAP;
689+ if(!nt_conv_local2wc(icd, (char*)board_name,
690+ board_nm_buf, sizeof(board_nm_buf)))
691+ goto ERROR_TRAP;
692+
693+ thread_datap =
694+ thread_data_alloc(res_no, dat_nm_buf, board_nm_buf);
695+ if(!thread_datap)
696+ goto ERROR_TRAP;
697+
698+ linkp = nt_link_add_data(result_linkp, thread_datap);
699+ if(!linkp){
700+ nt_usr_db_thread_data_free(thread_datap);
701+ goto ERROR_TRAP;
702+ }
703+ if(!result_linkp)
704+ result_linkp = linkp;
705+
706+ }
707+ if(SQLITE_DONE == rc){
708+ result = TRUE;
709+ }
710+ERROR_TRAP:
711+ if(icd != (iconv_t)-1)
712+ iconv_close(icd);
713+ if(stmt)
714+ sqlite3_finalize(stmt);
715+ nt_usr_db_close(db_handle);
716+ if(!result && result_linkp){
717+ nt_all_link_free(result_linkp,
718+ nt_usr_db_thread_data_free);
719+ result_linkp = NULL;
720+ }
721+ return result_linkp;
722+}
723+
615724 static BOOL nt_remove_thread_data(nt_link_tp *threadpp,
616725 const wchar_t *dat_name)
617726 {
@@ -709,7 +818,9 @@ static BOOL usr_tbl_create(sqlite3 *dbp)
709818
710819
711820 static nt_usr_db_thread_data_tp
712- thread_data_alloc(int read_count, const wchar_t *dat_name)
821+ thread_data_alloc(int read_count,
822+ const wchar_t *dat_name,
823+ const wchar_t *board_name)
713824 {
714825 nt_usr_db_thread_data_tp datap;
715826 wchar_t *wc;
@@ -726,6 +837,17 @@ static nt_usr_db_thread_data_tp
726837 return NULL;
727838 }
728839 datap->dat_name = wc;
840+ if(board_name){
841+ wc = nt_w_str_clone(board_name);
842+ if(!wc){
843+ free(datap->dat_name);
844+ free(datap);
845+ return NULL;
846+ }
847+ datap->board_name = wc;
848+ }else{
849+ datap->board_name = NULL;
850+ }
729851 datap->read_count = read_count;
730852 return datap;
731853 }
@@ -735,5 +857,7 @@ void nt_usr_db_thread_data_free(void *ptr)
735857 nt_usr_db_thread_data_tp datap =
736858 (nt_usr_db_thread_data_tp)ptr;
737859 free(datap->dat_name);
860+ if(datap->board_name)
861+ free(datap->board_name);
738862 free(ptr);
739863 }
--- a/src/utils/nt_std_t.c
+++ b/src/utils/nt_std_t.c
@@ -159,7 +159,7 @@ void* nt_map_remove(nt_map_handle handle, const wchar_t *key)
159159 return NULL;
160160 }
161161
162-int nt_map_get_count(nt_enum_handle handle)
162+int nt_map_get_count(nt_map_handle handle)
163163 {
164164 nt_map_tp mapp;
165165 assert(handle);
@@ -170,6 +170,29 @@ int nt_map_get_count(nt_enum_handle handle)
170170 return nt_link_num(mapp->key_value_list);
171171 }
172172
173+nt_link_tp nt_map_get_values(nt_map_handle handle)
174+{
175+ nt_map_tp mapp;
176+ assert(handle);
177+ assert(handle->chk_sum == NT_MAP_CHK_SUM);
178+ mapp = (nt_map_tp)handle;
179+ nt_link_tp linkp, wlinkp, rlinkp;
180+ nt_w_key_value_tp kvp;
181+
182+ rlinkp = NULL;
183+
184+ if(mapp->key_value_list){
185+ linkp = mapp->key_value_list;
186+ do{
187+ kvp = (nt_w_key_value_tp)linkp->data;
188+ wlinkp = nt_link_add_data(rlinkp, kvp->value);
189+ if(wlinkp && !rlinkp)
190+ rlinkp = wlinkp;
191+ linkp = linkp->next;
192+ }while(linkp != mapp->key_value_list);
193+ }
194+ return rlinkp;
195+}
173196
174197 nt_enum_handle nt_enum_set(nt_link_tp linkp)
175198 {
@@ -498,6 +521,12 @@ nt_link_tp nt_link_copy(nt_link_tp src_linkp)
498521 return resultp;
499522 }
500523
524+int nt_link_wcscmp_fnc(void *lhs, void *rhs)
525+{
526+ return wcscmp((const wchar_t *)lhs, (const wchar_t *)rhs);
527+}
528+
529+
501530 void nt_all_link_free(nt_link_tp ptr, nt_memfree_fn free_func)
502531 {
503532 nt_link_tp linkp;
Show on old repository browser