2 * This file part of StarDict - A international dictionary for GNOME.
3 * http://stardict.sourceforge.net
4 * Copyright (C) 2006 Hu Zheng <huzheng_001@163.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <glib/gi18n.h>
28 #include "sockets.hpp"
30 #include "getuint32.h"
32 #include "stardict_client.hpp"
34 #define PROTOCOL_VERSION "0.3"
36 #define CODE_HELLO 220 /* text msg-id */
37 #define CODE_GOODBYE 221 /* Closing Connection */
38 #define CODE_OK 250 /* ok */
39 #define CODE_TEMPORARILY_UNAVAILABLE 420 /* server unavailable */
40 #define CODE_SYNTAX_ERROR 500 /* syntax, command not recognized */
41 #define CODE_DENIED 521
42 #define CODE_DICTMASK_NOTSET 522
44 unsigned int STARDICT::Cmd::next_seq = 1;
46 sigc::signal<void, const char *> StarDictClient::on_error_;
47 sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_lookup_end_;
48 sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_floatwin_lookup_end_;
49 sigc::signal<void, const char *> StarDictClient::on_register_end_;
50 sigc::signal<void, const char *> StarDictClient::on_getdictmask_end_;
51 sigc::signal<void, const char *> StarDictClient::on_dirinfo_end_;
52 sigc::signal<void, const char *> StarDictClient::on_dictinfo_end_;
53 sigc::signal<void, int> StarDictClient::on_maxdictcount_end_;
54 sigc::signal<void, std::list<char *> *> StarDictClient::on_previous_end_;
55 sigc::signal<void, std::list<char *> *> StarDictClient::on_next_end_;
57 static void arg_escape(std::string &earg, const char *arg)
63 } else if (*arg==' ') {
65 } else if (*arg=='\n') {
74 STARDICT::Cmd::Cmd(int cmd, ...)
76 this->seq = this->next_seq;
78 this->reading_status = 0;
85 const char *client_name = va_arg( ap, const char * );
86 std::string earg1, earg2;
87 arg_escape(earg1, PROTOCOL_VERSION);
88 arg_escape(earg2, client_name);
89 this->data = g_strdup_printf("client %s %s\n", earg1.c_str(), earg2.c_str());
94 const char *user = va_arg( ap, const char * );
95 const char *passwd = va_arg( ap, const char * );
96 const char *email = va_arg( ap, const char * );
97 std::string earg1, earg2, earg3;
98 arg_escape(earg1, user);
99 arg_escape(earg2, passwd);
100 arg_escape(earg3, email);
101 this->data = g_strdup_printf("register %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
104 /*case CMD_CHANGE_PASSWD:
106 const char *user = va_arg( ap, const char * );
107 const char *old_passwd = va_arg( ap, const char * );
108 const char *new_passwd = va_arg( ap, const char * );
109 std::string earg1, earg2, earg3;
110 arg_escape(earg1, user);
111 arg_escape(earg2, old_passwd);
112 arg_escape(earg3, new_passwd);
113 this->data = g_strdup_printf("change_password %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
117 this->auth = new AuthInfo();
118 this->auth->user = va_arg( ap, const char * );
119 this->auth->passwd = va_arg( ap, const char * );
124 arg_escape(earg, va_arg( ap, const char * ));
125 this->data = g_strdup_printf("lookup %s 30\n", earg.c_str());
126 this->lookup_response = NULL;
132 arg_escape(earg, va_arg( ap, const char * ));
133 this->data = g_strdup_printf("previous %s 15\n", earg.c_str());
134 this->wordlist_response = NULL;
140 arg_escape(earg, va_arg( ap, const char * ));
141 this->data = g_strdup_printf("next %s 30\n", earg.c_str());
142 this->wordlist_response = NULL;
148 arg_escape(earg, va_arg( ap, const char * ));
149 this->data = g_strdup_printf("query %s\n", earg.c_str());
150 this->lookup_response = NULL;
153 case CMD_SELECT_QUERY:
156 arg_escape(earg, va_arg( ap, const char * ));
157 this->data = g_strdup_printf("selectquery %s\n", earg.c_str());
158 this->lookup_response = NULL;
161 case CMD_SMART_QUERY:
164 arg_escape(earg, va_arg( ap, const char * ));
165 int BeginPos = va_arg( ap, int );
166 this->data = g_strdup_printf("smartquery %s %d\n", earg.c_str(), BeginPos);
167 this->lookup_response = NULL;
173 arg_escape(earg, va_arg( ap, const char * ));
174 this->data = g_strdup_printf("define %s\n", earg.c_str());
175 this->lookup_response = NULL;
178 case CMD_SET_DICT_MASK:
181 arg_escape(earg, va_arg( ap, const char * ));
182 this->data = g_strdup_printf("setdictmask %s\n", earg.c_str());
185 case CMD_GET_DICT_MASK:
186 this->data = g_strdup("getdictmask\n");
188 /*case CMD_SET_COLLATE_FUNC:
191 arg_escape(earg, va_arg( ap, const char * ));
192 this->data = g_strdup_printf("setcollatefunc %s\n", earg.c_str());
195 case CMD_GET_COLLATE_FUNC:
196 this->data = g_strdup("getcollatefunc\n");
198 case CMD_SET_LANGUAGE:
201 arg_escape(earg, va_arg( ap, const char * ));
202 this->data = g_strdup_printf("setlanguage %s\n", earg.c_str());
205 case CMD_GET_LANGUAGE:
206 this->data = g_strdup("getlanguage\n");
211 arg_escape(earg, va_arg( ap, const char * ));
212 this->data = g_strdup_printf("setemail %s\n", earg.c_str());
216 this->data = g_strdup("getemail\n");
218 case CMD_GET_USER_LEVEL:
219 this->data = g_strdup("getuserlevel\n");
221 case CMD_MAX_DICT_COUNT:
222 this->data = g_strdup("maxdictcount\n");
227 arg_escape(earg, va_arg( ap, const char * ));
228 this->data = g_strdup_printf("dirinfo %s\n", earg.c_str());
234 arg_escape(earg, va_arg( ap, const char * ));
235 this->data = g_strdup_printf("dictinfo %s\n", earg.c_str());
238 /*case CMD_USER_LEVEL:
240 std::string earg1, earg2, earg3;
241 arg_escape(earg1, va_arg( ap, const char * ));
242 arg_escape(earg2, va_arg( ap, const char * ));
243 arg_escape(earg3, va_arg( ap, const char * ));
244 this->data = g_strdup_printf("userlevel %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
248 this->data = g_strdup("quit\n");
254 STARDICT::LookupResponse::DictResponse::DictResponse()
259 STARDICT::LookupResponse::DictResponse::~DictResponse()
262 for (std::list<DictResult *>::iterator i = dict_result_list.begin(); i != dict_result_list.end(); ++i) {
267 STARDICT::LookupResponse::DictResponse::DictResult::DictResult()
272 STARDICT::LookupResponse::DictResponse::DictResult::~DictResult()
275 for (std::list<WordResult *>::iterator i = word_result_list.begin(); i != word_result_list.end(); ++i) {
280 STARDICT::LookupResponse::DictResponse::DictResult::WordResult::WordResult()
285 STARDICT::LookupResponse::DictResponse::DictResult::WordResult::~WordResult()
288 for (std::list<char *>::iterator i = datalist.begin(); i != datalist.end(); ++i) {
293 STARDICT::LookupResponse::~LookupResponse()
295 if (listtype == ListType_List) {
296 for (std::list<char *>::iterator i = wordlist->begin(); i != wordlist->end(); ++i) {
300 } else if (listtype == ListType_Tree) {
301 for (std::list<WordTreeElement *>::iterator i = wordtree->begin(); i != wordtree->end(); ++i) {
302 g_free((*i)->bookname);
303 for (std::list<char *>::iterator j = (*i)->wordlist.begin(); j != (*i)->wordlist.end(); ++j) {
312 STARDICT::Cmd::~Cmd()
314 if (this->command == CMD_AUTH) {
319 if (this->command == CMD_LOOKUP || this->command == CMD_DEFINE || this->command == CMD_SELECT_QUERY || this->command == CMD_SMART_QUERY) {
320 delete this->lookup_response;
321 } else if (this->command == CMD_PREVIOUS || this->command == CMD_NEXT) {
322 if (this->wordlist_response) {
323 for (std::list<char *>::iterator i = this->wordlist_response->begin(); i != this->wordlist_response->end(); ++i) {
326 delete this->wordlist_response;
331 StarDictCache::StarDictCache()
333 str_pool.resize(str_pool_size);
334 for (size_t i = 0; i< str_pool_size; i++) {
337 cur_str_pool_pos = 0;
339 lookup_response_pool.resize(lookup_response_pool_size);
340 for (size_t i = 0; i< lookup_response_pool_size; i++) {
341 lookup_response_pool[i] = NULL;
343 cur_lookup_response_pool_pos = 0;
346 StarDictCache::~StarDictCache()
351 void StarDictCache::clean_all_cache()
353 for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
360 clean_cache_lookup_response();
363 void StarDictCache::clean_cache_lookup_response()
365 for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) {
367 delete ((*i)->lookup_response);
374 char *StarDictCache::get_cache_str(const char *key_str)
376 for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
378 if ((*i)->key == key_str)
385 STARDICT::LookupResponse *StarDictCache::get_cache_lookup_response(const char *key_str)
387 for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) {
389 if ((*i)->key == key_str)
390 return (*i)->lookup_response;
396 void StarDictCache::clean_cache_str(const char *key_str)
398 for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
400 if ((*i)->key == key_str) {
410 void StarDictCache::save_cache_str(const char *key_str, char *data)
412 if (str_pool[cur_str_pool_pos]) {
413 g_free(str_pool[cur_str_pool_pos]->data);
414 delete str_pool[cur_str_pool_pos];
416 str_pool[cur_str_pool_pos] = new StrElement();
417 str_pool[cur_str_pool_pos]->key = key_str;
418 str_pool[cur_str_pool_pos]->data = data;
420 if (cur_str_pool_pos == str_pool_size)
421 cur_str_pool_pos = 0;
424 void StarDictCache::save_cache_lookup_response(const char *key_str, STARDICT::LookupResponse *lookup_response)
426 if (lookup_response_pool[cur_lookup_response_pool_pos]) {
427 delete lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response;
428 delete lookup_response_pool[cur_lookup_response_pool_pos];
430 lookup_response_pool[cur_lookup_response_pool_pos] = new LookupResponseElement();
431 lookup_response_pool[cur_lookup_response_pool_pos]->key = key_str;
432 lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response = lookup_response;
433 cur_lookup_response_pool_pos++;
434 if (cur_lookup_response_pool_pos == lookup_response_pool_size)
435 cur_lookup_response_pool_pos = 0;
438 StarDictClient::StarDictClient()
444 is_connected_ = false;
447 StarDictClient::~StarDictClient()
452 void StarDictClient::set_server(const char *host, int port)
454 if (host_ != host || port_ != port) {
457 host_resolved = false;
462 void StarDictClient::set_auth(const char *user, const char *md5passwd)
464 if (user_ != user || md5passwd_ != md5passwd) {
466 md5passwd_ = md5passwd;
471 bool StarDictClient::try_cache(STARDICT::Cmd *c)
473 if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE || c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY) {
474 STARDICT::LookupResponse *res = get_cache_lookup_response(c->data);
476 if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE)
477 on_lookup_end_.emit(res, 0);
478 else if (c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY)
479 on_floatwin_lookup_end_.emit(res, 0);
486 if (c->command == STARDICT::CMD_PREVIOUS || c->command == STARDICT::CMD_NEXT) {
487 // Not implemented yet.
490 char *data = get_cache_str(c->data);
492 switch (c->command) {
493 case STARDICT::CMD_DIR_INFO:
494 on_dirinfo_end_.emit(data);
496 case STARDICT::CMD_DICT_INFO:
497 on_dictinfo_end_.emit(data);
499 case STARDICT::CMD_GET_DICT_MASK:
500 on_getdictmask_end_.emit(data);
502 case STARDICT::CMD_MAX_DICT_COUNT:
503 on_maxdictcount_end_.emit(atoi(data));
513 void StarDictClient::send_commands(int num, ...)
516 if (!is_connected_) {
518 c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows");
520 c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux");
522 cmdlist.push_back(c);
523 if (!user_.empty() && !md5passwd_.empty()) {
524 c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str());
525 cmdlist.push_back(c);
530 for (int i = 0; i< num; i++) {
531 c = va_arg( ap, STARDICT::Cmd *);
532 cmdlist.push_back(c);
535 if (!is_connected_) {
536 waiting_banner_ = true;
541 void StarDictClient::try_cache_or_send_commands(int num, ...)
544 std::list<STARDICT::Cmd *> send_cmdlist;
547 for (int i = 0; i< num; i++) {
548 c = va_arg( ap, STARDICT::Cmd *);
550 send_cmdlist.push_back(c);
554 if (send_cmdlist.empty())
557 if (!is_connected_) {
559 c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows");
561 c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux");
563 cmdlist.push_back(c);
564 if (!user_.empty() && !md5passwd_.empty()) {
565 c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str());
566 cmdlist.push_back(c);
569 for (std::list<STARDICT::Cmd *>::iterator i = send_cmdlist.begin(); i!= send_cmdlist.end(); ++i) {
570 cmdlist.push_back(*i);
572 if (!is_connected_) {
573 waiting_banner_ = true;
578 void StarDictClient::write_str(const char *str, GError **err)
580 int len = strlen(str);
585 res = g_io_channel_write_chars(channel_, str+(len - left_byte), left_byte, &bytes_written, err);
586 if (res == G_IO_STATUS_ERROR) {
590 left_byte -= bytes_written;
592 res = g_io_channel_flush(channel_, err);
593 if (res == G_IO_STATUS_ERROR) {
596 if (out_source_id_ == 0)
597 out_source_id_ = g_io_add_watch(channel_, GIOCondition(G_IO_OUT), on_io_out_event, this);
600 void StarDictClient::request_command()
602 reading_type_ = READ_LINE;
603 if (cmdlist.empty()) {
604 cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT));
606 STARDICT::Cmd *c = cmdlist.front();
607 switch (c->command) {
608 case STARDICT::CMD_AUTH:
610 struct MD5Context ctx;
611 unsigned char digest[16];
615 MD5Update(&ctx, (const unsigned char*)cmd_reply.daemonStamp.c_str(), cmd_reply.daemonStamp.length());
616 MD5Update(&ctx, (const unsigned char*)(c->auth->passwd.c_str()), c->auth->passwd.length());
617 MD5Final(digest, &ctx );
618 for (i = 0; i < 16; i++)
619 sprintf( hex+2*i, "%02x", digest[i] );
621 std::string earg1, earg2;
622 arg_escape(earg1, c->auth->user.c_str());
623 arg_escape(earg2, hex);
624 char *data = g_strdup_printf("auth %s %s\n", earg1.c_str(), earg2.c_str());
626 write_str(data, &err);
629 on_error_.emit(err->message);
638 write_str(c->data, &err);
640 on_error_.emit(err->message);
650 void StarDictClient::clean_command()
652 for (std::list<STARDICT::Cmd *>::iterator i=cmdlist.begin(); i!=cmdlist.end(); ++i) {
658 void StarDictClient::connect()
661 on_resolved(this, true, sa);
663 Socket::resolve(host_, this, on_resolved);
667 void StarDictClient::on_resolved(gpointer data, bool resolved, in_addr_t sa_)
669 StarDictClient *oStarDictClient = (StarDictClient *)data;
671 static bool showed_once = false;
674 gchar *mes = g_strdup_printf("Can not reslove %s: %s\n",
675 oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str());
682 if (oStarDictClient->host_resolved == false) {
683 oStarDictClient->sa = sa_;
684 oStarDictClient->host_resolved = true;
687 oStarDictClient->sd_ = Socket::socket();
689 if (oStarDictClient->sd_ == -1) {
690 std::string str = "Can not create socket: " + Socket::get_error_msg();
691 on_error_.emit(str.c_str());
694 Socket::connect(oStarDictClient->sd_, sa_, oStarDictClient->port_, oStarDictClient, on_connected);
697 void StarDictClient::on_connected(gpointer data, bool succeeded)
699 StarDictClient *oStarDictClient = (StarDictClient *)data;
701 static bool showed_once = false;
704 gchar *mes = g_strdup_printf("Can not connect to %s: %s\n",
705 oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str());
712 oStarDictClient->channel_ = g_io_channel_win32_new_socket(oStarDictClient->sd_);
714 oStarDictClient->channel_ = g_io_channel_unix_new(oStarDictClient->sd_);
717 g_io_channel_set_encoding(oStarDictClient->channel_, NULL, NULL);
719 /* make sure that the channel is non-blocking */
720 int flags = g_io_channel_get_flags(oStarDictClient->channel_);
721 flags |= G_IO_FLAG_NONBLOCK;
723 g_io_channel_set_flags(oStarDictClient->channel_, GIOFlags(flags), &err);
725 g_io_channel_unref(oStarDictClient->channel_);
726 oStarDictClient->channel_ = NULL;
727 gchar *str = g_strdup_printf("Unable to set the channel as non-blocking: %s", err->message);
734 oStarDictClient->is_connected_ = true;
735 oStarDictClient->waiting_banner_ = true;
736 oStarDictClient->reading_type_ = READ_LINE;
737 oStarDictClient->in_source_id_ = g_io_add_watch(oStarDictClient->channel_, GIOCondition(G_IO_IN | G_IO_ERR), on_io_in_event, oStarDictClient);
740 void StarDictClient::disconnect()
744 g_source_remove(in_source_id_);
747 if (out_source_id_) {
748 g_source_remove(out_source_id_);
753 g_io_channel_shutdown(channel_, TRUE, NULL);
754 g_io_channel_unref(channel_);
761 is_connected_ = false;
764 gboolean StarDictClient::on_io_out_event(GIOChannel *ch, GIOCondition cond,
767 StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data);
769 GIOStatus res = g_io_channel_flush(stardict_client->channel_, &err);
770 if (res == G_IO_STATUS_AGAIN) {
773 on_error_.emit(err->message);
776 stardict_client->out_source_id_ = 0;
780 gboolean StarDictClient::on_io_in_event(GIOChannel *ch, GIOCondition cond,
783 StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data);
785 if (!stardict_client->channel_) {
786 //g_warning("No channel available\n");
789 if (cond & G_IO_ERR) {
791 g_strdup_printf("Connection failed to the dictionary server at %s:%d",
792 stardict_client->host_.c_str(), stardict_client->port_);
795 stardict_client->disconnect();
804 if (!stardict_client->channel_)
807 if (stardict_client->reading_type_ == READ_SIZE) {
809 res = g_io_channel_read_chars(stardict_client->channel_, stardict_client->size_data+(stardict_client->size_count-stardict_client->size_left), stardict_client->size_left, &bytes_read, &err);
810 if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) {
812 gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message);
817 stardict_client->disconnect();
821 stardict_client->size_left -= bytes_read;
822 if (stardict_client->size_left == 0)
823 result = stardict_client->parse(stardict_client->size_data);
827 if (stardict_client->reading_type_ == READ_LINE)
828 g_io_channel_set_line_term(stardict_client->channel_, "\n", 1);
829 else if (stardict_client->reading_type_ == READ_STRING)
830 g_io_channel_set_line_term(stardict_client->channel_, "", 1);
832 res = g_io_channel_read_line(stardict_client->channel_, &line,
834 if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) {
836 gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message);
841 stardict_client->disconnect();
849 //truncate the line terminator before parsing
851 result = stardict_client->parse(line);
854 stardict_client->disconnect();
862 int StarDictClient::parse_banner(gchar *line)
866 if (status != CODE_HELLO) {
867 if (status == CODE_TEMPORARILY_UNAVAILABLE) {
868 printf("Server temporarily unavailable!\n");
870 printf("Unexpected status code %d\n", status);
875 p = strrchr(line, ' ');
878 cmd_reply.daemonStamp = p;
883 int StarDictClient::parse_command_client(gchar *line)
887 if (status != CODE_OK) {
888 gchar *str = g_strdup_printf("Client denied: %s", line);
896 int StarDictClient::parse_command_auth(gchar *line)
900 if (status != CODE_OK) {
901 gchar *str = g_strdup_printf(_("Authentication denied: %s"), line);
909 int StarDictClient::parse_command_register(gchar *line)
913 if (status != CODE_OK) {
914 gchar *str = g_strdup_printf(_("Register failed: %s"), line);
919 on_register_end_.emit(_("Register success!"));
923 int StarDictClient::parse_command_quit(gchar *line)
927 if (status != CODE_GOODBYE) {
932 int StarDictClient::parse_command_setdictmask(gchar *line)
936 if (status != CODE_OK) {
937 gchar *str = g_strdup_printf("Set Dict Mask failed: %s", line);
942 clean_cache_str("getdictmask\n");
943 clean_cache_lookup_response();
947 int StarDictClient::parse_command_getdictmask(STARDICT::Cmd* cmd, gchar *buf)
949 if (cmd->reading_status == 0) {
952 if (status != CODE_OK) {
954 on_error_.emit(_("You haven't setup the account. Please open the \"Net Dict\" page in the Preferences dialog and register an account first."));
958 cmd->reading_status = 1;
959 reading_type_ = READ_STRING;
960 } else if (cmd->reading_status == 1) {
961 on_getdictmask_end_.emit(buf);
962 save_cache_str(cmd->data, buf);
968 int StarDictClient::parse_command_dirinfo(STARDICT::Cmd* cmd, gchar *buf)
970 if (cmd->reading_status == 0) {
973 if (status != CODE_OK) {
974 gchar *str = g_strdup_printf("Get dir info failed: %s", buf);
981 cmd->reading_status = 1;
982 reading_type_ = READ_STRING;
983 } else if (cmd->reading_status == 1) {
984 on_dirinfo_end_.emit(buf);
985 save_cache_str(cmd->data, buf);
991 int StarDictClient::parse_command_dictinfo(STARDICT::Cmd* cmd, gchar *buf)
993 if (cmd->reading_status == 0) {
996 if (status != CODE_OK) {
997 gchar *str = g_strdup_printf("Get dict info failed: %s", buf);
1004 cmd->reading_status = 1;
1005 reading_type_ = READ_STRING;
1006 } else if (cmd->reading_status == 1) {
1007 on_dictinfo_end_.emit(buf);
1008 save_cache_str(cmd->data, buf);
1014 int StarDictClient::parse_command_maxdictcount(STARDICT::Cmd* cmd, gchar *buf)
1016 if (cmd->reading_status == 0) {
1019 if (status != CODE_OK) {
1020 gchar *str = g_strdup_printf("Get max dict count failed: %s", buf);
1022 on_error_.emit(str);
1027 cmd->reading_status = 1;
1028 reading_type_ = READ_STRING;
1029 } else if (cmd->reading_status == 1) {
1030 on_maxdictcount_end_.emit(atoi(buf));
1031 save_cache_str(cmd->data, buf);
1037 int StarDictClient::parse_wordlist(STARDICT::Cmd* cmd, gchar *buf)
1039 if (cmd->reading_status == 0) { // Read code.
1043 if (status != CODE_OK) {
1046 cmd->wordlist_response = new std::list<char *>;
1047 cmd->reading_status = 1;
1048 reading_type_ = READ_STRING;
1049 } else if (cmd->reading_status == 1) {
1052 if (cmd->command == STARDICT::CMD_PREVIOUS) {
1053 on_previous_end_.emit(cmd->wordlist_response);
1056 on_next_end_.emit(cmd->wordlist_response);
1060 cmd->wordlist_response->push_back(buf);
1066 int StarDictClient::parse_dict_result(STARDICT::Cmd* cmd, gchar *buf)
1068 if (cmd->reading_status == 0) { // Read code.
1072 if (status != CODE_OK) {
1073 if (status == CODE_DICTMASK_NOTSET) {
1074 on_error_.emit(_("You haven't chosen any dictionaries, please choose some by clicking \"Manage Dict\"->\"Network dictionaries\"->\"Add\"."));
1080 cmd->lookup_response = new STARDICT::LookupResponse();
1081 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_None;
1082 cmd->reading_status = 1;
1083 reading_type_ = READ_STRING;
1084 } else if (cmd->reading_status == 1) { // Read original word.
1085 cmd->lookup_response->dict_response.oword = buf;
1086 cmd->reading_status = 2;
1087 } else if (cmd->reading_status == 2) { // Read book name.
1090 if (cmd->command == STARDICT::CMD_DEFINE) {
1091 on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
1092 save_cache_lookup_response(cmd->data, cmd->lookup_response);
1093 cmd->lookup_response = NULL;
1095 } else if ( cmd->command == STARDICT::CMD_SELECT_QUERY || cmd->command == STARDICT::CMD_SMART_QUERY) {
1096 on_floatwin_lookup_end_.emit(cmd->lookup_response, cmd->seq);
1097 save_cache_lookup_response(cmd->data, cmd->lookup_response);
1098 cmd->lookup_response = NULL;
1101 cmd->reading_status = 6;
1102 reading_type_ = READ_STRING;
1104 struct STARDICT::LookupResponse::DictResponse::DictResult *dict_result = new STARDICT::LookupResponse::DictResponse::DictResult();
1105 dict_result->bookname = buf;
1106 cmd->lookup_response->dict_response.dict_result_list.push_back(dict_result);
1107 cmd->reading_status = 3;
1109 } else if (cmd->reading_status == 3) { // Read word.
1112 cmd->reading_status = 2;
1114 struct STARDICT::LookupResponse::DictResponse::DictResult::WordResult *word_result = new STARDICT::LookupResponse::DictResponse::DictResult::WordResult();
1115 word_result->word = buf;
1116 cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.push_back(word_result);;
1117 cmd->reading_status = 4;
1118 reading_type_ = READ_SIZE;
1119 size_data = (char *)g_malloc(sizeof(guint32));
1120 size_count = size_left = sizeof(guint32);
1122 } else if (cmd->reading_status == 4) {
1123 guint32 datasize = g_ntohl(get_uint32(buf));
1124 memcpy(buf, &datasize, sizeof(guint32));
1125 if (datasize == 0) {
1127 cmd->reading_status = 3;
1128 reading_type_ = READ_STRING;
1130 cmd->reading_status = 5;
1131 size_data = (char *)g_realloc(buf, datasize + sizeof(guint32));
1132 size_count = datasize + sizeof(guint32);
1133 size_left = datasize;
1135 } else if (cmd->reading_status == 5) {
1136 cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.back()->datalist.push_back(buf);
1137 cmd->reading_status = 4;
1138 size_data = (char *)g_malloc(sizeof(guint32));
1139 size_count = size_left = sizeof(guint32);
1140 } else if (cmd->reading_status == 6) {
1141 if (strcmp(buf, "d") == 0) {
1142 cmd->reading_status = 8;
1143 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Tree;
1144 cmd->lookup_response->wordtree = new std::list<STARDICT::LookupResponse::WordTreeElement *>;
1146 cmd->reading_status = 7;
1147 if (strcmp(buf, "r") == 0)
1148 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Rule_List;
1149 else if (strcmp(buf, "g") == 0)
1150 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Regex_List;
1151 else if (strcmp(buf, "f") == 0)
1152 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Fuzzy_List;
1154 cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_List;
1155 cmd->lookup_response->wordlist = new std::list<char *>;
1158 } else if (cmd->reading_status == 7) {
1161 on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
1162 save_cache_lookup_response(cmd->data, cmd->lookup_response);
1163 cmd->lookup_response = NULL;
1166 cmd->lookup_response->wordlist->push_back(buf);
1168 } else if (cmd->reading_status == 8) {
1171 on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
1172 save_cache_lookup_response(cmd->data, cmd->lookup_response);
1173 cmd->lookup_response = NULL;
1176 STARDICT::LookupResponse::WordTreeElement *element = new STARDICT::LookupResponse::WordTreeElement();
1177 element->bookname = buf;
1178 cmd->lookup_response->wordtree->push_back(element);
1179 cmd->reading_status = 9;
1181 } else if (cmd->reading_status == 9) {
1184 cmd->reading_status = 8;
1186 cmd->lookup_response->wordtree->back()->wordlist.push_back(buf);
1192 bool StarDictClient::parse(gchar *line)
1195 if (waiting_banner_) {
1196 waiting_banner_ = false;
1197 result = parse_banner(line);
1204 STARDICT::Cmd* cmd = cmdlist.front();
1205 switch (cmd->command) {
1206 case STARDICT::CMD_CLIENT:
1207 result = parse_command_client(line);
1210 case STARDICT::CMD_AUTH:
1211 result = parse_command_auth(line);
1214 case STARDICT::CMD_REGISTER:
1215 result = parse_command_register(line);
1218 case STARDICT::CMD_GET_DICT_MASK:
1219 result = parse_command_getdictmask(cmd, line);
1221 case STARDICT::CMD_SET_DICT_MASK:
1222 result = parse_command_setdictmask(line);
1224 case STARDICT::CMD_DIR_INFO:
1225 result = parse_command_dirinfo(cmd, line);
1227 case STARDICT::CMD_DICT_INFO:
1228 result = parse_command_dictinfo(cmd, line);
1230 case STARDICT::CMD_MAX_DICT_COUNT:
1231 result = parse_command_maxdictcount(cmd, line);
1233 case STARDICT::CMD_DEFINE:
1234 case STARDICT::CMD_LOOKUP:
1235 case STARDICT::CMD_SELECT_QUERY:
1236 case STARDICT::CMD_SMART_QUERY:
1237 result = parse_dict_result(cmd, line);
1239 case STARDICT::CMD_PREVIOUS:
1240 case STARDICT::CMD_NEXT:
1241 result = parse_wordlist(cmd, line);
1243 case STARDICT::CMD_QUIT:
1244 result = parse_command_quit(line);
1256 cmdlist.pop_front();
1257 if (cmdlist.empty()) {
1258 cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT));