Bug Summary

File:cafe-dictionary/libgdict/./gdict-client-context.c
Warning:line 1411, column 11
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gdict-client-context.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cafe-dictionary/libgdict -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Gdict" -D DATADIR="/usr/share" -D LIBDIR="/usr/lib" -D SYSCONFDIR="/usr/etc" -D PREFIX="/usr" -D CAFELOCALEDIR="/usr/share/locale" -D GDICTSOURCESDIR="/usr/share/cafe-dict/sources" -D GDICT_ENABLE_INTERNALS -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D G_DISABLE_CAST_CHECKS -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cafe-dictionary/libgdict -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-07-171227-94954-1 -x c ./gdict-client-context.c
1/* gdict-client-context.c -
2 *
3 * Copyright (C) 2005 Emmanuele Bassi <ebassi@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 */
19
20/**
21 * SECTION:gdict-client-context
22 * @short_description: DICT client transport
23 *
24 * #GdictClientContext is an implementation of the #GdictContext interface.
25 * It implements the Dictionary Protocol as defined by the RFC 2229 in order
26 * to connect to a dictionary server.
27 *
28 * You should rarely instantiate this object directely: use an appropriate
29 * #GdictSource instead.
30 */
31
32#ifdef HAVE_CONFIG_H1
33#include "config.h"
34#endif
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno(*__errno_location ()).h>
46#ifdef HAVE_UNISTD_H1
47#include <unistd.h>
48#endif
49
50#include <glib.h>
51#include <glib/gi18n-lib.h>
52
53#include "gdict-context-private.h"
54#include "gdict-context.h"
55#include "gdict-client-context.h"
56#include "gdict-enum-types.h"
57#include "gdict-marshal.h"
58#include "gdict-debug.h"
59#include "gdict-utils.h"
60#include "gdict-private.h"
61
62typedef enum {
63 CMD_CLIENT,
64 CMD_SHOW_DB,
65 CMD_SHOW_STRAT,
66 CMD_SHOW_INFO, /* not implemented */
67 CMD_SHOW_SERVER, /* not implemented */
68 CMD_MATCH,
69 CMD_DEFINE,
70 CMD_STATUS, /* not implemented */
71 CMD_OPTION_MIME, /* not implemented */
72 CMD_AUTH, /* not implemented */
73 CMD_HELP, /* not implemented */
74 CMD_QUIT,
75
76 CMD_INVALID
77} GdictCommandType;
78#define IS_VALID_CMD(cmd)(((cmd) >= CMD_CLIENT) || ((cmd) < CMD_INVALID)) (((cmd) >= CMD_CLIENT) || ((cmd) < CMD_INVALID))
79
80/* command strings: keep synced with the enum above! */
81static const gchar *dict_command_strings[] = {
82 "CLIENT",
83 "SHOW DB",
84 "SHOW STRAT",
85 "SHOW INFO",
86 "SHOW SERVER",
87 "MATCH",
88 "DEFINE",
89 "STATUS",
90 "OPTION MIME",
91 "AUTH",
92 "HELP",
93 "QUIT",
94
95 NULL((void*)0)
96};
97
98/* command stata */
99enum
100{
101 S_START,
102
103 S_STATUS,
104 S_DATA,
105
106 S_FINISH
107};
108
109typedef struct
110{
111 GdictCommandType cmd_type;
112
113 gchar *cmd_string;
114 guint state;
115
116 /* optional parameters passed to the command */
117 gchar *database;
118 gchar *strategy;
119 gchar *word;
120
121 /* buffer used to hold the reply from the server */
122 GString *buffer;
123
124 gpointer data;
125 GDestroyNotify data_destroy;
126} GdictCommand;
127
128/* The default string to be passed to the CLIENT command */
129#define GDICT_DEFAULT_CLIENT"CAFE Dictionary (" "1.25.0" ")" "CAFE Dictionary (" VERSION"1.25.0" ")"
130
131/* Default server:port couple */
132#define GDICT_DEFAULT_HOSTNAME"dict.org" "dict.org"
133#define GDICT_DEFAULT_PORT2628 2628
134
135/* make the hostname lookup expire every five minutes */
136#define HOSTNAME_LOOKUP_EXPIRE300 300
137
138/* wait 30 seconds between connection and receiving data on the line */
139#define CONNECTION_TIMEOUT_SEC30 30
140
141enum
142{
143 PROP_0,
144
145 PROP_HOSTNAME,
146 PROP_PORT,
147 PROP_STATUS,
148 PROP_CLIENT_NAME
149};
150
151enum
152{
153 CONNECTED,
154 DISCONNECTED,
155
156 LAST_SIGNAL
157};
158
159static guint gdict_client_context_signals[LAST_SIGNAL] = { 0 };
160
161struct _GdictClientContextPrivate
162{
163#ifdef ENABLE_IPV61
164 struct sockaddr_storage sockaddr;
165 struct addrinfo *host6info;
166#else
167 struct sockaddr_in sockaddr;
168#endif
169 struct hostent *hostinfo;
170
171 time_t last_lookup;
172
173 gchar *hostname;
174 gint port;
175
176 GIOChannel *channel;
177 guint source_id;
178 guint timeout_id;
179
180 GdictCommand *command;
181 GQueue *commands_queue;
182
183 gchar *client_name;
184
185 GdictStatusCode status_code;
186
187 guint local_only : 1;
188 guint is_connecting : 1;
189};
190
191static void gdict_client_context_iface_init (GdictContextIface *iface);
192
193G_DEFINE_TYPE_WITH_CODE (GdictClientContext,static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
194 gdict_client_context,static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
195 G_TYPE_OBJECT,static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
196 G_ADD_PRIVATE (GdictClientContext)static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
197 G_IMPLEMENT_INTERFACE (GDICT_TYPE_CONTEXT,static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
198 gdict_client_context_iface_init))static void gdict_client_context_init (GdictClientContext *self
); static void gdict_client_context_class_init (GdictClientContextClass
*klass); static GType gdict_client_context_get_type_once (void
); static gpointer gdict_client_context_parent_class = ((void
*)0); static gint GdictClientContext_private_offset; static void
gdict_client_context_class_intern_init (gpointer klass) { gdict_client_context_parent_class
= g_type_class_peek_parent (klass); if (GdictClientContext_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictClientContext_private_offset
); gdict_client_context_class_init ((GdictClientContextClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
gdict_client_context_get_instance_private (GdictClientContext
*self) { return (((gpointer) ((guint8*) (self) + (glong) (GdictClientContext_private_offset
)))); } GType gdict_client_context_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = gdict_client_context_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType gdict_client_context_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("GdictClientContext"
), sizeof (GdictClientContextClass), (GClassInitFunc)(void (*
)(void)) gdict_client_context_class_intern_init, sizeof (GdictClientContext
), (GInstanceInitFunc)(void (*)(void)) gdict_client_context_init
, (GTypeFlags) 0); { {{ GdictClientContext_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (GdictClientContextPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) gdict_client_context_iface_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (gdict_context_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
;
199
200/* GObject methods */
201static void gdict_client_context_set_property (GObject *object,
202 guint prop_id,
203 const GValue *value,
204 GParamSpec *pspec);
205static void gdict_client_context_get_property (GObject *object,
206 guint prop_id,
207 GValue *value,
208 GParamSpec *pspec);
209static void gdict_client_context_finalize (GObject *object);
210
211/* GdictContext methods */
212static gboolean gdict_client_context_get_databases (GdictContext *context,
213 GError **error);
214static gboolean gdict_client_context_get_strategies (GdictContext *context,
215 GError **error);
216static gboolean gdict_client_context_define_word (GdictContext *context,
217 const gchar *database,
218 const gchar *word,
219 GError **error);
220static gboolean gdict_client_context_match_word (GdictContext *context,
221 const gchar *database,
222 const gchar *strategy,
223 const gchar *word,
224 GError **error);
225
226static void gdict_client_context_clear_hostinfo (GdictClientContext *context);
227static gboolean gdict_client_context_lookup_server (GdictClientContext *context,
228 GError **error);
229static gboolean gdict_client_context_io_watch_cb (GIOChannel *source,
230 GIOCondition condition,
231 GdictClientContext *context);
232static gboolean gdict_client_context_parse_line (GdictClientContext *context,
233 const gchar *buffer);
234static void gdict_client_context_disconnect (GdictClientContext *context);
235static void gdict_client_context_force_disconnect (GdictClientContext *context);
236static void gdict_client_context_real_connected (GdictClientContext *context);
237static void gdict_client_context_real_disconnected (GdictClientContext *context);
238
239static GdictCommand *gdict_command_new (GdictCommandType cmd_type);
240static void gdict_command_free (GdictCommand *cmd);
241
242
243
244GQuark
245gdict_client_context_error_quark (void)
246{
247 return g_quark_from_static_string ("gdict-client-context-error-quark");
248}
249
250static void
251gdict_client_context_iface_init (GdictContextIface *iface)
252{
253 iface->get_databases = gdict_client_context_get_databases;
254 iface->get_strategies = gdict_client_context_get_strategies;
255 iface->match_word = gdict_client_context_match_word;
256 iface->define_word = gdict_client_context_define_word;
257}
258
259static void
260gdict_client_context_class_init (GdictClientContextClass *klass)
261{
262 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
263
264 gobject_class->set_property = gdict_client_context_set_property;
265 gobject_class->get_property = gdict_client_context_get_property;
266 gobject_class->finalize = gdict_client_context_finalize;
267
268 g_object_class_override_property (gobject_class,
269 GDICT_CONTEXT_PROP_LOCAL_ONLY,
270 "local-only");
271
272 /**
273 * GdictClientContext:client-name
274 *
275 * The name of the client using this context; it will be advertised when
276 * connecting to the dictionary server.
277 *
278 * Since: 1.0
279 */
280 g_object_class_install_property (gobject_class,
281 PROP_CLIENT_NAME,
282 g_param_spec_string ("client-name",
283 _("Client Name")((char *) g_dgettext ("cafe-utils", "Client Name")),
284 _("The name of the client of the context object")((char *) g_dgettext ("cafe-utils", "The name of the client of the context object"
))
,
285 NULL((void*)0),
286 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
287 /**
288 * GdictClientContext:hostname
289 *
290 * The hostname of the dictionary server to connect to.
291 *
292 * Since: 1.0
293 */
294 g_object_class_install_property (gobject_class,
295 PROP_HOSTNAME,
296 g_param_spec_string ("hostname",
297 _("Hostname")((char *) g_dgettext ("cafe-utils", "Hostname")),
298 _("The hostname of the dictionary server to connect to")((char *) g_dgettext ("cafe-utils", "The hostname of the dictionary server to connect to"
))
,
299 NULL((void*)0),
300 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
301 /**
302 * GdictClientContext:port
303 *
304 * The port of the dictionary server to connect to.
305 *
306 * Since: 1.0
307 */
308 g_object_class_install_property (gobject_class,
309 PROP_PORT,
310 g_param_spec_uint ("port",
311 _("Port")((char *) g_dgettext ("cafe-utils", "Port")),
312 _("The port of the dictionary server to connect to")((char *) g_dgettext ("cafe-utils", "The port of the dictionary server to connect to"
))
,
313 0,
314 65535,
315 GDICT_DEFAULT_PORT2628,
316 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
317 /**
318 * GdictClientContext:status
319 *
320 * The status code as returned by the dictionary server.
321 *
322 * Since: 1.0
323 */
324 g_object_class_install_property (gobject_class,
325 PROP_STATUS,
326 g_param_spec_enum ("status",
327 _("Status")((char *) g_dgettext ("cafe-utils", "Status")),
328 _("The status code as returned by the dictionary server")((char *) g_dgettext ("cafe-utils", "The status code as returned by the dictionary server"
))
,
329 GDICT_TYPE_STATUS_CODE(gdict_status_code_get_type()),
330 GDICT_STATUS_INVALID,
331 G_PARAM_READABLE));
332
333 /**
334 * GdictClientContext::connected
335 * @client: the object which received the signal
336 *
337 * Emitted when a #GdictClientContext has successfully established a
338 * connection with a dictionary server.
339 *
340 * Since: 1.0
341 */
342 gdict_client_context_signals[CONNECTED] =
343 g_signal_new ("connected",
344 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
345 G_SIGNAL_RUN_LAST,
346 G_STRUCT_OFFSET (GdictClientContextClass, connected)((glong) __builtin_offsetof(GdictClientContextClass, connected
))
,
347 NULL((void*)0), NULL((void*)0),
348 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
349 G_TYPE_NONE((GType) ((1) << (2))), 0);
350 /**
351 * GdictClientContext::disconnected
352 * @client: the object which received the signal
353 *
354 * Emitted when a #GdictClientContext has disconnected from a dictionary
355 * server.
356 *
357 * Since: 1.0
358 */
359 gdict_client_context_signals[DISCONNECTED] =
360 g_signal_new ("disconnected",
361 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
362 G_SIGNAL_RUN_LAST,
363 G_STRUCT_OFFSET (GdictClientContextClass, disconnected)((glong) __builtin_offsetof(GdictClientContextClass, disconnected
))
,
364 NULL((void*)0), NULL((void*)0),
365 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
366 G_TYPE_NONE((GType) ((1) << (2))), 0);
367
368 klass->connected = gdict_client_context_real_connected;
369 klass->disconnected = gdict_client_context_real_disconnected;
370}
371
372static void
373gdict_client_context_init (GdictClientContext *context)
374{
375 GdictClientContextPrivate *priv;
376
377 priv = gdict_client_context_get_instance_private (context);
378 context->priv = priv;
379
380 priv->hostname = NULL((void*)0);
381 priv->port = 0;
382
383 priv->hostinfo = NULL((void*)0);
384#ifdef ENABLE_IPV61
385 priv->host6info = NULL((void*)0);
386#endif
387
388 priv->last_lookup = (time_t) -1;
389
390 priv->is_connecting = FALSE(0);
391 priv->local_only = FALSE(0);
392
393 priv->status_code = GDICT_STATUS_INVALID;
394
395 priv->client_name = NULL((void*)0);
396
397 priv->command = NULL((void*)0);
398 priv->commands_queue = g_queue_new ();
399}
400
401static void
402gdict_client_context_set_property (GObject *object,
403 guint prop_id,
404 const GValue *value,
405 GParamSpec *pspec)
406{
407 GdictClientContextPrivate *priv = gdict_client_context_get_instance_private (GDICT_CLIENT_CONTEXT (object)((((GdictClientContext*) (void *) ((object))))));
408
409 switch (prop_id)
410 {
411 case PROP_HOSTNAME:
412 if (priv->hostname)
413 g_free (priv->hostname);
414 priv->hostname = g_strdup (g_value_get_string (value))g_strdup_inline (g_value_get_string (value));
415 gdict_client_context_clear_hostinfo (GDICT_CLIENT_CONTEXT (object)((((GdictClientContext*) (void *) ((object))))));
416 break;
417 case PROP_PORT:
418 priv->port = g_value_get_uint (value);
419 break;
420 case PROP_CLIENT_NAME:
421 if (priv->client_name)
422 g_free (priv->client_name);
423 priv->client_name = g_strdup (g_value_get_string (value))g_strdup_inline (g_value_get_string (value));
424 break;
425 case GDICT_CONTEXT_PROP_LOCAL_ONLY:
426 priv->local_only = g_value_get_boolean (value);
427 break;
428 default:
429 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "./gdict-client-context.c", 429, ("property"), _glib__property_id
, _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance
*) (_glib__pspec))->g_class))->g_type)))), (g_type_name
((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
430 break;
431 }
432}
433
434static void
435gdict_client_context_get_property (GObject *object,
436 guint prop_id,
437 GValue *value,
438 GParamSpec *pspec)
439{
440 GdictClientContextPrivate *priv = gdict_client_context_get_instance_private (GDICT_CLIENT_CONTEXT (object)((((GdictClientContext*) (void *) ((object))))));
441
442 switch (prop_id)
443 {
444 case PROP_STATUS:
445 g_value_set_enum (value, priv->status_code);
446 break;
447 case PROP_HOSTNAME:
448 g_value_set_string (value, priv->hostname);
449 break;
450 case PROP_PORT:
451 g_value_set_uint (value, priv->port);
452 break;
453 case PROP_CLIENT_NAME:
454 g_value_set_string (value, priv->client_name);
455 break;
456 case GDICT_CONTEXT_PROP_LOCAL_ONLY:
457 g_value_set_boolean (value, priv->local_only);
458 break;
459 default:
460 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "./gdict-client-context.c", 460, ("property"), _glib__property_id
, _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance
*) (_glib__pspec))->g_class))->g_type)))), (g_type_name
((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
461 break;
462 }
463}
464
465static void
466gdict_client_context_finalize (GObject *object)
467{
468 GdictClientContext *context = GDICT_CLIENT_CONTEXT (object)((((GdictClientContext*) (void *) ((object)))));
469 GdictClientContextPrivate *priv = context->priv;
470
471 /* force disconnection */
472 gdict_client_context_force_disconnect (context);
473
474 if (priv->command)
475 gdict_command_free (priv->command);
476
477 if (priv->commands_queue)
478 {
479 g_queue_free_full (priv->commands_queue,
480 (GDestroyNotify) gdict_command_free);
481 priv->commands_queue = NULL((void*)0);
482 }
483
484 if (priv->client_name)
485 g_free (priv->client_name);
486
487 if (priv->hostname)
488 g_free (priv->hostname);
489
490#ifdef ENABLE_IPV61
491 if (priv->host6info)
492 freeaddrinfo (priv->host6info);
493#endif
494
495 /* chain up parent's finalize method */
496 G_OBJECT_CLASS (gdict_client_context_parent_class)((((GObjectClass*) (void *) ((gdict_client_context_parent_class
)))))
->finalize (object);
497}
498
499/**
500 * gdict_client_context_new:
501 * @hostname: the hostname of a dictionary server, or %NULL for the
502 * default server
503 * @port: port to be used when connecting to the dictionary server,
504 * or -1 for the default port
505 *
506 * Creates a new #GdictClientContext object for @hostname. Use this
507 * object to connect and query the dictionary server using the Dictionary
508 * Protocol as defined by RFC 2229.
509 *
510 * Return value: the newly created #GdictClientContext object. You should
511 * free it using g_object_unref().
512 */
513GdictContext *
514gdict_client_context_new (const gchar *hostname,
515 gint port)
516{
517 return g_object_new (GDICT_TYPE_CLIENT_CONTEXT(gdict_client_context_get_type ()),
518 "hostname", (hostname != NULL((void*)0) ? hostname : GDICT_DEFAULT_HOSTNAME"dict.org"),
519 "port", (port != -1 ? port : GDICT_DEFAULT_PORT2628),
520 "client-name", GDICT_DEFAULT_CLIENT"CAFE Dictionary (" "1.25.0" ")",
521 NULL((void*)0));
522}
523
524/**
525 * gdict_client_context_set_hostname:
526 * @context: a #GdictClientContext
527 * @hostname: the hostname of a Dictionary server, or %NULL
528 *
529 * Sets @hostname as the hostname of the dictionary server to be used.
530 * If @hostname is %NULL, the default dictionary server will be used.
531 */
532void
533gdict_client_context_set_hostname (GdictClientContext *context,
534 const gchar *hostname)
535{
536 g_return_if_fail (GDICT_IS_CLIENT_CONTEXT (context))do{ (void)0; }while (0);
537
538 g_object_set (G_OBJECT (context)((((GObject*) (void *) ((context))))),
539 "hostname", (hostname != NULL((void*)0) ? hostname : GDICT_DEFAULT_HOSTNAME"dict.org"),
540 NULL((void*)0));
541}
542
543/**
544 * gdict_client_context_get_hostname:
545 * @context: a #GdictClientContext
546 *
547 * Gets the hostname of the dictionary server used by @context.
548 *
549 * Return value: the hostname of a dictionary server. The returned string is
550 * owned by the #GdictClientContext object and should never be modified or
551 * freed.
552 */
553const gchar *
554gdict_client_context_get_hostname (GdictClientContext *context)
555{
556 gchar *hostname;
557
558 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), NULL)do{ (void)0; }while (0);
559
560 g_object_get (G_OBJECT (context)((((GObject*) (void *) ((context))))), "hostname", &hostname, NULL((void*)0));
561
562 return hostname;
563}
564
565/**
566 * gdict_client_context_set_port:
567 * @context: a #GdictClientContext
568 * @port: port of the dictionary server to be used, or -1
569 *
570 * Sets the port of the dictionary server to be used when connecting.
571 *
572 * If @port is -1, the default port will be used.
573 */
574void
575gdict_client_context_set_port (GdictClientContext *context,
576 gint port)
577{
578 g_return_if_fail (GDICT_IS_CLIENT_CONTEXT (context))do{ (void)0; }while (0);
579
580 g_object_set (G_OBJECT (context)((((GObject*) (void *) ((context))))),
581 "port", (port != -1 ? port : GDICT_DEFAULT_PORT2628),
582 NULL((void*)0));
583}
584
585/**
586 * gdict_client_context_get_port:
587 * @context: a #GdictClientContext
588 *
589 * Gets the port of the dictionary server used by @context.
590 *
591 * Return value: the number of the port.
592 */
593guint
594gdict_client_context_get_port (GdictClientContext *context)
595{
596 guint port;
597
598 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), -1)do{ (void)0; }while (0);
599
600 g_object_get (G_OBJECT (context)((((GObject*) (void *) ((context))))), "port", &port, NULL((void*)0));
601
602 return port;
603}
604
605/**
606 * gdict_client_context_set_client:
607 * @context: a #GdictClientContext
608 * @client: the client name to use, or %NULL
609 *
610 * Sets @client as the client name to be used when advertising ourselves when
611 * a connection the the dictionary server has been established.
612 * If @client is %NULL, the default client name will be used.
613 */
614void
615gdict_client_context_set_client (GdictClientContext *context,
616 const gchar *client)
617{
618 g_return_if_fail (GDICT_IS_CLIENT_CONTEXT (context))do{ (void)0; }while (0);
619
620 g_object_set (G_OBJECT (context)((((GObject*) (void *) ((context))))),
621 "client-name", (client != NULL((void*)0) ? client : GDICT_DEFAULT_CLIENT"CAFE Dictionary (" "1.25.0" ")"),
622 NULL((void*)0));
623}
624
625/**
626 * gdict_client_context_get_client:
627 * @context: a #GdictClientContext
628 *
629 * Gets the client name used by @context. See gdict_client_context_set_client().
630 *
631 * Return value: the client name. The returned string is owned by the
632 * #GdictClientContext object and should never be modified or freed.
633 */
634const gchar *
635gdict_client_context_get_client (GdictClientContext *context)
636{
637 gchar *client_name;
638
639 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), NULL)do{ (void)0; }while (0);
640
641 g_object_get (G_OBJECT (context)((((GObject*) (void *) ((context))))), "client-name", &client_name, NULL((void*)0));
642
643 return client_name;
644}
645
646/* creates a new command to be sent to the dictionary server */
647static GdictCommand *
648gdict_command_new (GdictCommandType cmd_type)
649{
650 GdictCommand *retval;
651
652 g_assert (IS_VALID_CMD (cmd_type))do { (void) 0; } while (0);
653
654 retval = g_slice_new0 (GdictCommand)((GdictCommand*) g_slice_alloc0 (sizeof (GdictCommand)));
655
656 retval->cmd_type = cmd_type;
657 retval->state = S_START;
658
659 return retval;
660}
661
662static void
663gdict_command_free (GdictCommand *cmd)
664{
665 if (!cmd)
666 return;
667
668 g_free (cmd->cmd_string);
669
670 switch (cmd->cmd_type)
671 {
672 case CMD_CLIENT:
673 case CMD_QUIT:
674 break;
675 case CMD_SHOW_DB:
676 case CMD_SHOW_STRAT:
677 break;
678 case CMD_MATCH:
679 g_free (cmd->database);
680 g_free (cmd->strategy);
681 g_free (cmd->word);
682 break;
683 case CMD_DEFINE:
684 g_free (cmd->database);
685 g_free (cmd->word);
686 break;
687 default:
688 break;
689 }
690
691 if (cmd->buffer)
692 g_string_free (cmd->buffer, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(cmd->buffer), ((!(0)))) : g_string_free_and_steal (cmd->
buffer)) : (g_string_free) ((cmd->buffer), ((!(0)))))
;
693
694 if (cmd->data_destroy)
695 cmd->data_destroy (cmd->data);
696
697 g_slice_free (GdictCommand, cmd)do { if (1) g_slice_free1 (sizeof (GdictCommand), (cmd)); else
(void) ((GdictCommand*) 0 == (cmd)); } while (0)
;
698}
699
700/* push @command into the head of the commands queue; the command queue is
701 * a FIFO-like pipe: commands go into the head and are retrieved from the
702 * tail.
703 */
704static gboolean
705gdict_client_context_push_command (GdictClientContext *context,
706 GdictCommand *command)
707{
708 GdictClientContextPrivate *priv;
709
710 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
711 g_assert (command != NULL)do { (void) 0; } while (0);
712
713 priv = context->priv;
714
715 /* avoid pushing a command twice */
716 if (g_queue_find (priv->commands_queue, command))
717 {
718 g_warning ("gdict_client_context_push_command() called on a command already in queue\n");
719 return FALSE(0);
720 }
721
722 GDICT_NOTE (DICT, "Pushing command ('%s') into the queue...",
723 dict_command_strings[command->cmd_type]);
724
725 g_queue_push_head (priv->commands_queue, command);
726
727 return TRUE(!(0));
728}
729
730static GdictCommand *
731gdict_client_context_pop_command (GdictClientContext *context)
732{
733 GdictClientContextPrivate *priv;
734 GdictCommand *retval;
735
736 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
737
738 priv = context->priv;
739
740 retval = (GdictCommand *) g_queue_pop_tail (priv->commands_queue);
741 if (!retval)
742 return NULL((void*)0);
743
744 GDICT_NOTE (DICT, "Getting command ('%s') from the queue...",
745 dict_command_strings[retval->cmd_type]);
746
747 return retval;
748}
749
750/* send @command on the wire */
751static gboolean
752gdict_client_context_send_command (GdictClientContext *context,
753 GdictCommand *command,
754 GError **error)
755{
756 GdictClientContextPrivate *priv;
757 GError *write_error;
758 gsize written_bytes;
759 GIOStatus res;
760
761 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
762 g_assert (command != NULL && command->cmd_string != NULL)do { (void) 0; } while (0);
763
764 priv = context->priv;
765
766 if (!priv->channel)
767 {
768 GDICT_NOTE (DICT, "No connection established");
769
770 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
771 GDICT_CLIENT_CONTEXT_ERROR_NO_CONNECTION,
772 _("No connection to the dictionary server at '%s:%d'")((char *) g_dgettext ("cafe-utils", "No connection to the dictionary server at '%s:%d'"
))
,
773 priv->hostname,
774 priv->port);
775
776 return FALSE(0);
777 }
778
779 write_error = NULL((void*)0);
780 res = g_io_channel_write_chars (priv->channel,
781 command->cmd_string,
782 -1,
783 &written_bytes,
784 &write_error);
785 if (res != G_IO_STATUS_NORMAL)
786 {
787 g_propagate_error (error, write_error);
788
789 return FALSE(0);
790 }
791
792 /* force flushing of the write buffer */
793 g_io_channel_flush (priv->channel, NULL((void*)0));
794
795 GDICT_NOTE (DICT, "Wrote %"G_GSIZE_FORMAT" bytes to the channel", written_bytes);
796
797 return TRUE(!(0));
798}
799
800/* gdict_client_context_run_command: runs @command inside @context; this
801 * function builds the command string and then passes it to the dictionary
802 * server.
803 */
804static gboolean
805gdict_client_context_run_command (GdictClientContext *context,
806 GdictCommand *command,
807 GError **error)
808{
809 GdictClientContextPrivate *priv;
810 gchar *payload;
811 GError *send_error;
812 gboolean res;
813
814 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
815 g_assert (command != NULL)do { (void) 0; } while (0);
816 g_assert (IS_VALID_CMD (command->cmd_type))do { (void) 0; } while (0);
817
818 GDICT_NOTE (DICT, "GdictCommand command =\n"
819 "{\n"
820 " .cmd_type = '%02d' ('%s');\n"
821 " .database = '%s';\n"
822 " .strategy = '%s';\n"
823 " .word = '%s';\n"
824 "}\n",
825 command->cmd_type, dict_command_strings[command->cmd_type],
826 command->database ? command->database : "<none>",
827 command->strategy ? command->strategy : "<none>",
828 command->word ? command->word : "<none>");
829
830 priv = context->priv;
831
832 g_assert (priv->command == NULL)do { (void) 0; } while (0);
833
834 priv->command = command;
835
836 /* build the command string to be sent to the server */
837 switch (command->cmd_type)
838 {
839 case CMD_CLIENT:
840 payload = g_shell_quote (priv->client_name);
841 command->cmd_string = g_strdup_printf ("%s %s\r\n",
842 dict_command_strings[CMD_CLIENT],
843 payload);
844 g_free (payload);
845 break;
846 case CMD_QUIT:
847 command->cmd_string = g_strdup_printf ("%s\r\n",
848 dict_command_strings[CMD_QUIT]);
849 break;
850 case CMD_SHOW_DB:
851 command->cmd_string = g_strdup_printf ("%s\r\n",
852 dict_command_strings[CMD_SHOW_DB]);
853 break;
854 case CMD_SHOW_STRAT:
855 command->cmd_string = g_strdup_printf ("%s\r\n",
856 dict_command_strings[CMD_SHOW_STRAT]);
857 break;
858 case CMD_MATCH:
859 g_assert (command->word)do { (void) 0; } while (0);
860 payload = g_shell_quote (command->word);
861 command->cmd_string = g_strdup_printf ("%s %s %s %s\r\n",
862 dict_command_strings[CMD_MATCH],
863 (command->database != NULL((void*)0) ? command->database : "!"),
864 (command->strategy != NULL((void*)0) ? command->strategy : "*"),
865 payload);
866 g_free (payload);
867 break;
868 case CMD_DEFINE:
869 g_assert (command->word)do { (void) 0; } while (0);
870 payload = g_shell_quote (command->word);
871 command->cmd_string = g_strdup_printf ("%s %s %s\r\n",
872 dict_command_strings[CMD_DEFINE],
873 (command->database != NULL((void*)0) ? command->database : "!"),
874 payload);
875 g_free (payload);
876 break;
877 default:
878 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
879 break;
880 }
881
882 g_assert (command->cmd_string)do { (void) 0; } while (0);
883
884 GDICT_NOTE (DICT, "Sending command ('%s') to the server",
885 dict_command_strings[command->cmd_type]);
886
887 send_error = NULL((void*)0);
888 res = gdict_client_context_send_command (context, command, &send_error);
889 if (!res)
890 {
891 g_propagate_error (error, send_error);
892
893 return FALSE(0);
894 }
895
896 return TRUE(!(0));
897}
898
899/* we use this signal to advertise ourselves to the dictionary server */
900static void
901gdict_client_context_real_connected (GdictClientContext *context)
902{
903 GdictCommand *cmd;
904
905 cmd = gdict_command_new (CMD_CLIENT);
906 cmd->state = S_FINISH;
907
908 /* the CLIENT command should be the first one in our queue, so we place
909 * it above all other commands the user might have issued between the
910 * first and the emission of the "connected" signal, by calling it
911 * directely.
912 */
913 gdict_client_context_run_command (context, cmd, NULL((void*)0));
914}
915
916static void
917clear_command_queue (GdictClientContext *context)
918{
919 GdictClientContextPrivate *priv = context->priv;
920
921 if (priv->commands_queue)
922 {
923 g_queue_free_full (priv->commands_queue,
924 (GDestroyNotify) gdict_command_free);
925 }
926
927 /* renew */
928 priv->commands_queue = g_queue_new ();
929}
930
931/* force a disconnection from the server */
932static void
933gdict_client_context_force_disconnect (GdictClientContext *context)
934{
935 GdictClientContextPrivate *priv = context->priv;
936
937 if (priv->timeout_id)
938 {
939 g_source_remove (priv->timeout_id);
940 priv->timeout_id = 0;
941 }
942
943 if (priv->source_id)
944 {
945 g_source_remove (priv->source_id);
946 priv->source_id = 0;
947 }
948
949 if (priv->channel)
950 {
951 g_io_channel_shutdown (priv->channel, TRUE(!(0)), NULL((void*)0));
952 g_io_channel_unref (priv->channel);
953
954 priv->channel = NULL((void*)0);
955 }
956
957 if (priv->command)
958 {
959 gdict_command_free (priv->command);
960 priv->command = NULL((void*)0);
961 }
962
963 clear_command_queue (context);
964}
965
966static void
967gdict_client_context_real_disconnected (GdictClientContext *context)
968{
969 gdict_client_context_force_disconnect (context);
970}
971
972/* clear the lookup data */
973static void
974gdict_client_context_clear_hostinfo (GdictClientContext *context)
975{
976 GdictClientContextPrivate *priv;
977
978 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
979
980 priv = context->priv;
981
982#ifdef ENABLE_IPV61
983 if (!priv->host6info)
984 return;
985#endif
986
987 if (!priv->hostinfo)
988 return;
989
990#ifdef ENABLE_IPV61
991 freeaddrinfo (priv->host6info);
992#endif
993 priv->hostinfo = NULL((void*)0);
994}
995
996/* gdict_client_context_lookup_server: perform an hostname lookup in order to
997 * connect to the dictionary server
998 */
999static gboolean
1000gdict_client_context_lookup_server (GdictClientContext *context,
1001 GError **error)
1002{
1003 GdictClientContextPrivate *priv;
1004 gboolean is_expired = FALSE(0);
1005 time_t now;
1006
1007 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
1008
1009 priv = context->priv;
1010
1011 /* we need the hostname, at this point */
1012 g_assert (priv->hostname != NULL)do { (void) 0; } while (0);
1013
1014 time (&now);
1015 if (now >= (priv->last_lookup + HOSTNAME_LOOKUP_EXPIRE300))
1016 is_expired = TRUE(!(0));
1017
1018 /* we already have resolved the hostname */
1019#ifdef ENABLE_IPV61
1020 if (priv->host6info && !is_expired)
1021 return TRUE(!(0));
1022#endif
1023
1024 if (priv->hostinfo && !is_expired)
1025 return TRUE(!(0));
1026
1027 /* clear any previously acquired lookup data */
1028 gdict_client_context_clear_hostinfo (context);
1029
1030 GDICT_NOTE (DICT, "Looking up hostname '%s'", priv->hostname);
1031
1032#ifdef ENABLE_IPV61
1033 if (_gdict_has_ipv6 ())
1034 {
1035 struct addrinfo hints, *res;
1036
1037 GDICT_NOTE (DICT, "Hostname '%s' look-up (using IPv6)", priv->hostname);
1038
1039 memset (&hints, 0, sizeof (hints));
1040 hints.ai_socktype = SOCK_STREAMSOCK_STREAM;
1041
1042 if (getaddrinfo (priv->hostname, NULL((void*)0), &hints, &(priv->host6info)) == 0)
1043 {
1044 for (res = priv->host6info; res; res = res->ai_next)
1045 if (res->ai_family == AF_INET610 || res->ai_family == AF_INET2)
1046 break;
1047
1048 if (!res)
1049 {
1050 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1051 GDICT_CLIENT_CONTEXT_ERROR_LOOKUP,
1052 _("Lookup failed for hostname '%s': no suitable resources found")((char *) g_dgettext ("cafe-utils", "Lookup failed for hostname '%s': no suitable resources found"
))
,
1053 priv->hostname);
1054
1055 return FALSE(0);
1056 }
1057 else
1058 {
1059 if (res->ai_family == AF_INET610)
1060 memcpy (&((struct sockaddr_in6 *) &priv->sockaddr)->sin6_addr,
1061 &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr,
1062 sizeof (struct in6_addr));
1063
1064 if (res->ai_family == AF_INET2)
1065 memcpy (&((struct sockaddr_in *) &priv->sockaddr)->sin_addr,
1066 &((struct sockaddr_in *) res->ai_addr)->sin_addr,
1067 sizeof (struct in_addr));
1068
1069 priv->sockaddr.ss_family = res->ai_family;
1070
1071 GDICT_NOTE (DICT, "Hostname '%s' found (using IPv6)",
1072 priv->hostname);
1073
1074 priv->last_lookup = time (NULL((void*)0));
1075
1076 return TRUE(!(0));
1077 }
1078 }
1079 else
1080 {
1081 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1082 GDICT_CLIENT_CONTEXT_ERROR_LOOKUP,
1083 _("Lookup failed for host '%s': %s")((char *) g_dgettext ("cafe-utils", "Lookup failed for host '%s': %s"
))
,
1084 priv->hostname,
1085 gai_strerror (errno(*__errno_location ())));
1086
1087 return FALSE(0);
1088 }
1089 }
1090 else
1091 {
1092#endif /* ENABLE_IPV6 */
1093 /* if we don't support IPv6, fallback to usual IPv4 lookup */
1094
1095 GDICT_NOTE (DICT, "Hostname '%s' look-up (using IPv4)", priv->hostname);
1096
1097 ((struct sockaddr_in *) &priv->sockaddr)->sin_family = AF_INET2;
1098
1099 priv->hostinfo = gethostbyname (priv->hostname);
1100 if (priv->hostinfo)
1101 {
1102 memcpy (&((struct sockaddr_in *) &(priv->sockaddr))->sin_addr,
1103 priv->hostinfo->h_addrh_addr_list[0],
1104 priv->hostinfo->h_length);
1105
1106 GDICT_NOTE (DICT, "Hostname '%s' found (using IPv4)",
1107 priv->hostname);
1108
1109 priv->last_lookup = time (NULL((void*)0));
1110
1111 return TRUE(!(0));
1112 }
1113 else
1114 {
1115 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1116 GDICT_CLIENT_CONTEXT_ERROR_LOOKUP,
1117 _("Lookup failed for host '%s': host not found")((char *) g_dgettext ("cafe-utils", "Lookup failed for host '%s': host not found"
))
,
1118 priv->hostname);
1119
1120 return FALSE(0);
1121 }
1122#ifdef ENABLE_IPV61
1123 }
1124#endif
1125
1126 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1127
1128 return FALSE(0);
1129}
1130
1131/* gdict_client_context_parse_line: parses a line from the dictionary server
1132 * this is the core of the RFC2229 protocol implementation, here's where
1133 * the magic happens.
1134 */
1135static gboolean
1136gdict_client_context_parse_line (GdictClientContext *context,
1137 const gchar *buffer)
1138{
1139 GdictClientContextPrivate *priv;
1140 GError *server_error = NULL((void*)0);
1141
1142 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
1
Loop condition is false. Exiting loop
1143 g_assert (buffer != NULL)do { (void) 0; } while (0);
2
Loop condition is false. Exiting loop
1144
1145 priv = context->priv;
1146
1147 GDICT_NOTE (DICT, "parse buffer: '%s'", buffer);
1148
1149 /* connection is a special case: we don't have a command, so we just
1150 * make sure that the server replied with the correct code. WARNING:
1151 * the server might be shutting down or not available, so we must
1152 * take into account those responses too!
1153 */
1154 if (!priv->command)
3
Assuming field 'command' is non-null
4
Taking false branch
1155 {
1156 if (priv->status_code == GDICT_STATUS_CONNECT)
1157 {
1158 /* the server accepts our connection */
1159 g_signal_emit (context, gdict_client_context_signals[CONNECTED], 0);
1160
1161 return TRUE(!(0));
1162 }
1163 else if ((priv->status_code == GDICT_STATUS_SERVER_DOWN) ||
1164 (priv->status_code == GDICT_STATUS_SHUTDOWN))
1165 {
1166 /* the server is shutting down or is not available */
1167 g_set_error (&server_error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1168 GDICT_CLIENT_CONTEXT_ERROR_SERVER_DOWN,
1169 _("Unable to connect to the dictionary server "((char *) g_dgettext ("cafe-utils", "Unable to connect to the dictionary server "
"at '%s:%d'. The server replied with " "code %d (server down)"
))
1170 "at '%s:%d'. The server replied with "((char *) g_dgettext ("cafe-utils", "Unable to connect to the dictionary server "
"at '%s:%d'. The server replied with " "code %d (server down)"
))
1171 "code %d (server down)")((char *) g_dgettext ("cafe-utils", "Unable to connect to the dictionary server "
"at '%s:%d'. The server replied with " "code %d (server down)"
))
,
1172 priv->hostname,
1173 priv->port,
1174 priv->status_code);
1175
1176 g_signal_emit_by_name (context, "error", server_error);
1177
1178 g_error_free (server_error);
1179
1180 return TRUE(!(0));
1181 }
1182 else
1183 {
1184 GError *parse_error = NULL((void*)0);
1185
1186 g_set_error (&parse_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1187 GDICT_CONTEXT_ERROR_PARSE,
1188 _("Unable to parse the dictionary server reply\n: '%s'")((char *) g_dgettext ("cafe-utils", "Unable to parse the dictionary server reply\n: '%s'"
))
,
1189 buffer);
1190
1191 g_signal_emit_by_name (context, "error", parse_error);
1192
1193 g_error_free (parse_error);
1194
1195 return FALSE(0);
1196 }
1197 }
1198
1199 /* disconnection is another special case: the server replies with code
1200 * 221, and closes the connection; we emit the "disconnected" signal
1201 * and close the connection on our side.
1202 */
1203 if (priv->status_code == GDICT_STATUS_QUIT)
5
Assuming field 'status_code' is not equal to GDICT_STATUS_QUIT
6
Taking false branch
1204 {
1205 g_signal_emit (context, gdict_client_context_signals[DISCONNECTED], 0);
1206
1207 return TRUE(!(0));
1208 }
1209
1210 /* here we catch all the errors codes that the server might give us */
1211 server_error = NULL((void*)0);
1212 switch (priv->status_code)
7
Control jumps to the 'default' case at line 1319
1213 {
1214 case GDICT_STATUS_NO_MATCH:
1215 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1216 GDICT_CONTEXT_ERROR_NO_MATCH,
1217 _("No definitions found for '%s'")((char *) g_dgettext ("cafe-utils", "No definitions found for '%s'"
))
,
1218 priv->command->word);
1219
1220 GDICT_NOTE (DICT, "No match: %s", server_error->message);
1221
1222 g_signal_emit_by_name (context, "error", server_error);
1223
1224 g_error_free (server_error);
1225 server_error = NULL((void*)0);
1226
1227 priv->command->state = S_FINISH;
1228 break;
1229 case GDICT_STATUS_BAD_DATABASE:
1230 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1231 GDICT_CONTEXT_ERROR_INVALID_DATABASE,
1232 _("Invalid database '%s'")((char *) g_dgettext ("cafe-utils", "Invalid database '%s'")),
1233 priv->command->database);
1234
1235 GDICT_NOTE (DICT, "Bad DB: %s", server_error->message);
1236
1237 g_signal_emit_by_name (context, "error", server_error);
1238
1239 g_error_free (server_error);
1240 server_error = NULL((void*)0);
1241
1242 priv->command->state = S_FINISH;
1243 break;
1244 case GDICT_STATUS_BAD_STRATEGY:
1245 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1246 GDICT_CONTEXT_ERROR_INVALID_STRATEGY,
1247 _("Invalid strategy '%s'")((char *) g_dgettext ("cafe-utils", "Invalid strategy '%s'")),
1248 priv->command->strategy);
1249
1250 GDICT_NOTE (DICT, "Bad strategy: %s", server_error->message);
1251
1252 g_signal_emit_by_name (context, "error", server_error);
1253
1254 g_error_free (server_error);
1255 server_error = NULL((void*)0);
1256
1257 priv->command->state = S_FINISH;
1258 break;
1259 case GDICT_STATUS_BAD_COMMAND:
1260 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1261 GDICT_CONTEXT_ERROR_INVALID_COMMAND,
1262 _("Bad command '%s'")((char *) g_dgettext ("cafe-utils", "Bad command '%s'")),
1263 dict_command_strings[priv->command->cmd_type]);
1264
1265 GDICT_NOTE (DICT, "Bad command: %s", server_error->message);
1266
1267 g_signal_emit_by_name (context, "error", server_error);
1268
1269 g_error_free (server_error);
1270 server_error = NULL((void*)0);
1271
1272 priv->command->state = S_FINISH;
1273 break;
1274 case GDICT_STATUS_BAD_PARAMETERS:
1275 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1276 GDICT_CONTEXT_ERROR_INVALID_COMMAND,
1277 _("Bad parameters for command '%s'")((char *) g_dgettext ("cafe-utils", "Bad parameters for command '%s'"
))
,
1278 dict_command_strings[priv->command->cmd_type]);
1279
1280 GDICT_NOTE (DICT, "Bad params: %s", server_error->message);
1281
1282 g_signal_emit_by_name (context, "error", server_error);
1283
1284 g_error_free (server_error);
1285 server_error = NULL((void*)0);
1286
1287 priv->command->state = S_FINISH;
1288 break;
1289 case GDICT_STATUS_NO_DATABASES_PRESENT:
1290 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1291 GDICT_CONTEXT_ERROR_NO_DATABASES,
1292 _("No databases found on dictionary server at '%s'")((char *) g_dgettext ("cafe-utils", "No databases found on dictionary server at '%s'"
))
,
1293 priv->hostname);
1294
1295 GDICT_NOTE (DICT, "No DB: %s", server_error->message);
1296
1297 g_signal_emit_by_name (context, "error", server_error);
1298
1299 g_error_free (server_error);
1300 server_error = NULL((void*)0);
1301
1302 priv->command->state = S_FINISH;
1303 break;
1304 case GDICT_STATUS_NO_STRATEGIES_PRESENT:
1305 g_set_error (&server_error, GDICT_CONTEXT_ERROR(gdict_context_error_quark ()),
1306 GDICT_CONTEXT_ERROR_NO_STRATEGIES,
1307 _("No strategies found on dictionary server at '%s'")((char *) g_dgettext ("cafe-utils", "No strategies found on dictionary server at '%s'"
))
,
1308 priv->hostname);
1309
1310 GDICT_NOTE (DICT, "No strategies: %s", server_error->message);
1311
1312 g_signal_emit_by_name (context, "error", server_error);
1313
1314 g_error_free (server_error);
1315 server_error = NULL((void*)0);
1316
1317 priv->command->state = S_FINISH;
1318 break;
1319 default:
1320 GDICT_NOTE (DICT, "non-error code: %d", priv->status_code);
1321 break;
1322 }
1323
1324 /* server replied with 'ok' or the command has reached its FINISH state,
1325 * so now we are clear for destroying the current command and check if
1326 * there are other commands on the queue, and run them.
1327 */
1328 if ((priv->status_code == GDICT_STATUS_OK) ||
8
Assuming field 'status_code' is not equal to GDICT_STATUS_OK
10
Taking false branch
1329 (priv->command->state == S_FINISH))
9
Assuming field 'state' is not equal to S_FINISH
1330 {
1331 GdictCommand *new_command;
1332 GError *run_error;
1333 GdictCommandType last_cmd;
1334
1335 last_cmd = priv->command->cmd_type;
1336
1337 gdict_command_free (priv->command);
1338 priv->command = NULL((void*)0);
1339
1340 /* notify the end of a command - ignore CLIENT and QUIT commands, as
1341 * we issue them ourselves
1342 */
1343 if ((last_cmd != CMD_CLIENT) && (last_cmd != CMD_QUIT))
1344 g_signal_emit_by_name (context, "lookup-end");
1345
1346 /* pop the next command from the queue */
1347 new_command = gdict_client_context_pop_command (context);
1348 if (!new_command)
1349 {
1350 /* if the queue is empty, quit */
1351 gdict_client_context_disconnect (context);
1352 new_command = gdict_client_context_pop_command (context);
1353 }
1354
1355 run_error = NULL((void*)0);
1356 gdict_client_context_run_command (context, new_command, &run_error);
1357 if (run_error)
1358 {
1359 g_signal_emit_by_name (context, "error", run_error);
1360
1361 g_error_free (run_error);
1362 }
1363
1364 return TRUE(!(0));
1365 }
1366
1367 GDICT_NOTE (DICT, "check command %d ('%s')[state:%d]",
1368 priv->command->cmd_type,
1369 dict_command_strings[priv->command->cmd_type],
1370 priv->command->state);
1371
1372 /* check command type */
1373 switch (priv->command->cmd_type)
11
Control jumps to 'case CMD_SHOW_DB:' at line 1378
1374 {
1375 case CMD_CLIENT:
1376 case CMD_QUIT:
1377 break;
1378 case CMD_SHOW_DB:
1379 if (priv->status_code == GDICT_STATUS_N_DATABASES_PRESENT)
12
Assuming field 'status_code' is not equal to GDICT_STATUS_N_DATABASES_PRESENT
13
Taking false branch
1380 {
1381 gchar *p;
1382
1383 priv->command->state = S_DATA;
1384
1385 p = g_utf8_strchr (buffer, -1, ' ');
1386 if (p)
1387 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1388
1389 GDICT_NOTE (DICT, "server replied: %d databases found", atoi (p));
1390 }
1391 else if (0 == strcmp (buffer, "."))
14
Assuming the condition is false
15
Taking false branch
1392 priv->command->state = S_FINISH;
1393 else
1394 {
1395 GdictDatabase *db;
1396 gchar *name, *full, *p;
1397
1398 g_assert (priv->command->state == S_DATA)do { (void) 0; } while (0);
16
Loop condition is false. Exiting loop
1399
1400 /* first token: database name;
1401 * second token: database description;
1402 */
1403 name = (gchar *) buffer;
1404 if (!name
16.1
'name' is non-null
)
17
Taking false branch
1405 break;
1406
1407 p = g_utf8_strchr (name, -1, ' ');
18
Value assigned to 'p'
1408 if (p)
19
Assuming 'p' is null
20
Taking false branch
1409 *p = '\0';
1410
1411 full = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
21
Dereference of null pointer
1412
1413 if (full[0] == '\"')
1414 full = g_utf8_next_char (full)(char *)((full) + g_utf8_skip[*(const guchar *)(full)]);
1415
1416 p = g_utf8_strchr (full, -1, '\"');
1417 if (p)
1418 *p = '\0';
1419
1420 db = _gdict_database_new (name);
1421 db->full_name = g_strdup (full)g_strdup_inline (full);
1422
1423 g_signal_emit_by_name (context, "database-found", db);
1424
1425 gdict_database_unref (db);
1426 }
1427 break;
1428 case CMD_SHOW_STRAT:
1429 if (priv->status_code == GDICT_STATUS_N_STRATEGIES_PRESENT)
1430 {
1431 gchar *p;
1432
1433 priv->command->state = S_DATA;
1434
1435 p = g_utf8_strchr (buffer, -1, ' ');
1436 if (p)
1437 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1438
1439 GDICT_NOTE (DICT, "server replied: %d strategies found", atoi (p));
1440 }
1441 else if (0 == strcmp (buffer, "."))
1442 priv->command->state = S_FINISH;
1443 else
1444 {
1445 GdictStrategy *strat;
1446 gchar *name, *desc, *p;
1447
1448 g_assert (priv->command->state == S_DATA)do { (void) 0; } while (0);
1449
1450 name = (gchar *) buffer;
1451 if (!name)
1452 break;
1453
1454 p = g_utf8_strchr (name, -1, ' ');
1455 if (p)
1456 *p = '\0';
1457
1458 desc = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1459
1460 if (desc[0] == '\"')
1461 desc = g_utf8_next_char (desc)(char *)((desc) + g_utf8_skip[*(const guchar *)(desc)]);
1462
1463 p = g_utf8_strchr (desc, -1, '\"');
1464 if (p)
1465 *p = '\0';
1466
1467 strat = _gdict_strategy_new (name);
1468 strat->description = g_strdup (desc)g_strdup_inline (desc);
1469
1470 g_signal_emit_by_name (context, "strategy-found", strat);
1471
1472 gdict_strategy_unref (strat);
1473 }
1474 break;
1475 case CMD_DEFINE:
1476 if (priv->status_code == GDICT_STATUS_N_DEFINITIONS_RETRIEVED)
1477 {
1478 GdictDefinition *def;
1479 gchar *p;
1480
1481 priv->command->state = S_STATUS;
1482
1483 p = g_utf8_strchr (buffer, -1, ' ');
1484 if (p)
1485 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1486
1487 GDICT_NOTE (DICT, "server replied: %d definitions found", atoi (p));
1488
1489 def = _gdict_definition_new (atoi (p));
1490
1491 priv->command->data = def;
1492 priv->command->data_destroy = (GDestroyNotify) gdict_definition_unref;
1493 }
1494 else if (priv->status_code == GDICT_STATUS_WORD_DB_NAME)
1495 {
1496 GdictDefinition *def;
1497 gchar *word, *db_name, *db_full, *p;
1498
1499 word = (gchar *) buffer;
1500
1501 /* skip the status code */
1502 word = g_utf8_strchr (word, -1, ' ');
1503 word = g_utf8_next_char (word)(char *)((word) + g_utf8_skip[*(const guchar *)(word)]);
1504
1505 if (word[0] == '\"')
1506 word = g_utf8_next_char (word)(char *)((word) + g_utf8_skip[*(const guchar *)(word)]);
1507
1508 p = g_utf8_strchr (word, -1, '\"');
1509 if (p)
1510 *p = '\0';
1511
1512 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1513
1514 /* the database name is not protected by "" */
1515 db_name = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1516 if (!db_name)
1517 break;
1518
1519 p = g_utf8_strchr (db_name, -1, ' ');
1520 if (p)
1521 *p = '\0';
1522
1523 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1524
1525 db_full = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1526 if (!db_full)
1527 break;
1528
1529 if (db_full[0] == '\"')
1530 db_full = g_utf8_next_char (db_full)(char *)((db_full) + g_utf8_skip[*(const guchar *)(db_full)]);
1531
1532 p = g_utf8_strchr (db_full, -1, '\"');
1533 if (p)
1534 *p = '\0';
1535
1536 def = (GdictDefinition *) priv->command->data;
1537
1538 GDICT_NOTE (DICT, "{ word = '%s', db_name = '%s', db_full = '%s' }",
1539 word,
1540 db_name,
1541 db_full);
1542
1543 def->word = g_strdup (word)g_strdup_inline (word);
1544 def->database_name = g_strdup (db_name)g_strdup_inline (db_name);
1545 def->database_full = g_strdup (db_full)g_strdup_inline (db_full);
1546 def->definition = NULL((void*)0);
1547
1548 priv->command->state = S_DATA;
1549 }
1550 else if (strcmp (buffer, ".") == 0)
1551 {
1552 GdictDefinition *def;
1553 gint num;
1554
1555 g_assert (priv->command->state == S_DATA)do { (void) 0; } while (0);
1556
1557 def = (GdictDefinition *) priv->command->data;
1558 if (!def)
1559 break;
1560
1561 def->definition = g_string_free (priv->command->buffer, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((priv
->command->buffer), ((0))) : g_string_free_and_steal (priv
->command->buffer)) : (g_string_free) ((priv->command
->buffer), ((0))))
;
1562
1563 /* store the numer of definitions */
1564 num = def->total;
1565
1566 g_signal_emit_by_name (context, "definition-found", def);
1567
1568 gdict_definition_unref (def);
1569
1570 priv->command->buffer = NULL((void*)0);
1571 priv->command->data = _gdict_definition_new (num);
1572
1573 priv->command->state = S_STATUS;
1574 }
1575 else
1576 {
1577 g_assert (priv->command->state == S_DATA)do { (void) 0; } while (0);
1578
1579 if (!priv->command->buffer)
1580 priv->command->buffer = g_string_new (NULL((void*)0));
1581
1582 GDICT_NOTE (DICT, "appending to buffer:\n %s", buffer);
1583
1584 /* TODO - collapse '..' to '.' */
1585 g_string_append_printf (priv->command->buffer, "%s\n", buffer);
1586 }
1587 break;
1588 case CMD_MATCH:
1589 if (priv->status_code == GDICT_STATUS_N_MATCHES_FOUND)
1590 {
1591 gchar *p;
1592
1593 priv->command->state = S_DATA;
1594
1595 p = g_utf8_strchr (buffer, -1, ' ');
1596 if (p)
1597 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1598
1599 GDICT_NOTE (DICT, "server replied: %d matches found", atoi (p));
1600 }
1601 else if (0 == strcmp (buffer, "."))
1602 priv->command->state = S_FINISH;
1603 else
1604 {
1605 GdictMatch *match;
1606 gchar *word, *db_name, *p;
1607
1608 g_assert (priv->command->state == S_DATA)do { (void) 0; } while (0);
1609
1610 db_name = (gchar *) buffer;
1611 if (!db_name)
1612 break;
1613
1614 p = g_utf8_strchr (db_name, -1, ' ');
1615 if (p)
1616 *p = '\0';
1617
1618 word = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
1619
1620 if (word[0] == '\"')
1621 word = g_utf8_next_char (word)(char *)((word) + g_utf8_skip[*(const guchar *)(word)]);
1622
1623 p = g_utf8_strchr (word, -1, '\"');
1624 if (p)
1625 *p = '\0';
1626
1627 match = _gdict_match_new (word);
1628 match->database = g_strdup (db_name)g_strdup_inline (db_name);
1629
1630 g_signal_emit_by_name (context, "match-found", match);
1631
1632 gdict_match_unref (match);
1633 }
1634 break;
1635 default:
1636 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1637 break;
1638 }
1639
1640 return TRUE(!(0));
1641}
1642
1643/* retrieve the status code from the server response line */
1644static gint
1645get_status_code (const gchar *line,
1646 gint old_status)
1647{
1648 gchar *status;
1649 gint possible_status, retval;
1650
1651 if (strlen (line) < 3)
1652 return 0;
1653
1654 if (!g_unichar_isdigit (line[0]) ||
1655 !g_unichar_isdigit (line[1]) ||
1656 !g_unichar_isdigit (line[2]))
1657 return 0;
1658
1659 if (!g_unichar_isspace (line[3]))
1660 return 0;
1661
1662 status = g_strndup (line, 3);
1663 possible_status = atoi (status);
1664 g_free (status);
1665
1666 /* status whitelisting: sometimes, a database *cough* moby-thes *cough*
1667 * might return a number as first word; we do a small check here for
1668 * invalid status codes based on the previously set status; we don't check
1669 * the whole line, as we need only to be sure that the status code is
1670 * consistent with what we expect.
1671 */
1672 switch (old_status)
1673 {
1674 case GDICT_STATUS_WORD_DB_NAME:
1675 case GDICT_STATUS_N_MATCHES_FOUND:
1676 if (possible_status == GDICT_STATUS_OK)
1677 retval = possible_status;
1678 else
1679 retval = 0;
1680 break;
1681 case GDICT_STATUS_N_DEFINITIONS_RETRIEVED:
1682 if (possible_status == GDICT_STATUS_WORD_DB_NAME)
1683 retval = possible_status;
1684 else
1685 retval = 0;
1686 break;
1687 default:
1688 retval = possible_status;
1689 break;
1690 }
1691
1692 return retval;
1693}
1694
1695static gboolean
1696gdict_client_context_io_watch_cb (GIOChannel *channel,
1697 GIOCondition condition,
1698 GdictClientContext *context)
1699{
1700 GdictClientContextPrivate *priv;
1701
1702 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
1703 priv = context->priv;
1704
1705 /* since this is an asynchronous channel, we might end up here
1706 * even though the channel has been shut down.
1707 */
1708 if (!priv->channel)
1709 {
1710 g_warning ("No channel available\n");
1711
1712 return FALSE(0);
1713 }
1714
1715 if (priv->is_connecting)
1716 {
1717 priv->is_connecting = FALSE(0);
1718
1719 if (priv->timeout_id)
1720 {
1721 g_source_remove (priv->timeout_id);
1722 priv->timeout_id = 0;
1723 }
1724 }
1725
1726 if (condition & G_IO_ERR)
1727 {
1728 GError *err = NULL((void*)0);
1729
1730 g_set_error (&err, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1731 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1732 _("Connection failed to the dictionary server at %s:%d")((char *) g_dgettext ("cafe-utils", "Connection failed to the dictionary server at %s:%d"
))
,
1733 priv->hostname,
1734 priv->port);
1735
1736 g_signal_emit_by_name (context, "error", err);
1737
1738 g_error_free (err);
1739
1740 return FALSE(0);
1741 }
1742
1743 while (1)
1744 {
1745 GIOStatus res;
1746 guint status_code;
1747 GError *read_err;
1748 gsize len, term;
1749 gchar *line;
1750 gboolean parse_res;
1751
1752 /* we might sever the connection while still inside the read loop,
1753 * so we must check the state of the channel before actually doing
1754 * the line reading, otherwise we'll end up with death, destruction
1755 * and chaos on all earth. oh, and an assertion failed inside
1756 * g_io_channel_read_line().
1757 */
1758 if (!priv->channel)
1759 break;
1760
1761 read_err = NULL((void*)0);
1762 res = g_io_channel_read_line (priv->channel, &line, &len, &term, &read_err);
1763 if (res == G_IO_STATUS_ERROR)
1764 {
1765 if (read_err)
1766 {
1767 GError *err = NULL((void*)0);
1768
1769 g_set_error (&err, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1770 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1771 _("Error while reading reply from server:\n%s")((char *) g_dgettext ("cafe-utils", "Error while reading reply from server:\n%s"
))
,
1772 read_err->message);
1773
1774 g_signal_emit_by_name (context, "error", err);
1775
1776 g_error_free (err);
1777 g_error_free (read_err);
1778 }
1779
1780 gdict_client_context_force_disconnect (context);
1781
1782 return FALSE(0);
1783 }
1784
1785 if (len == 0)
1786 break;
1787
1788 /* truncate the line terminator before parsing */
1789 line[term] = '\0';
1790
1791 status_code = get_status_code (line, priv->status_code);
1792 if ((status_code == 0) || (GDICT_IS_VALID_STATUS_CODE (status_code)(((status_code) > GDICT_STATUS_INVALID) && ((status_code
) <= GDICT_STATUS_NO_STRATEGIES_PRESENT))
))
1793 {
1794 priv->status_code = status_code;
1795
1796 GDICT_NOTE (DICT, "new status = '%d'", priv->status_code);
1797 }
1798 else
1799 priv->status_code = GDICT_STATUS_INVALID;
1800
1801 /* notify changes only for valid status codes */
1802 if (priv->status_code != GDICT_STATUS_INVALID)
1803 g_object_notify (G_OBJECT (context)((((GObject*) (void *) ((context))))), "status");
1804
1805 parse_res = gdict_client_context_parse_line (context, line);
1806 if (!parse_res)
1807 {
1808 g_free (line);
1809
1810 g_warning ("Parsing failed");
1811
1812 gdict_client_context_force_disconnect (context);
1813
1814 return FALSE(0);
1815 }
1816
1817 g_free (line);
1818 }
1819
1820 return TRUE(!(0));
1821}
1822
1823static gboolean
1824check_for_connection (gpointer data)
1825{
1826 GdictClientContext *context = data;
1827
1828#if 0
1829 g_debug (G_STRLOC"./gdict-client-context.c" ":" "1829" ": checking for connection (is connecting:%s)",
1830 context->priv->is_connecting ? "true" : "false");
1831#endif
1832
1833 if (context == NULL((void*)0))
1834 return FALSE(0);
1835
1836 if (context->priv->is_connecting)
1837 {
1838 GError *err = NULL((void*)0);
1839
1840 GDICT_NOTE (DICT, "Forcing a disconnection due to timeout");
1841
1842 g_set_error (&err, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1843 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1844 _("Connection timeout for the dictionary server at '%s:%d'")((char *) g_dgettext ("cafe-utils", "Connection timeout for the dictionary server at '%s:%d'"
))
,
1845 context->priv->hostname,
1846 context->priv->port);
1847
1848 g_signal_emit_by_name (context, "error", err);
1849
1850 g_error_free (err);
1851
1852 gdict_client_context_force_disconnect (context);
1853 }
1854
1855 /* this is a one-off operation */
1856 return FALSE(0);
1857}
1858
1859static gboolean
1860gdict_client_context_connect (GdictClientContext *context,
1861 GError **error)
1862{
1863 GdictClientContextPrivate *priv;
1864 GError *lookup_error, *flags_error;
1865 gboolean res;
1866 gint sock_fd, sock_res;
1867 gsize addrlen;
1868 GIOFlags flags;
1869
1870 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), FALSE)do{ (void)0; }while (0);
1871
1872 priv = context->priv;
1873
1874 if (!priv->hostname)
1875 {
1876 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1877 GDICT_CLIENT_CONTEXT_ERROR_LOOKUP,
1878 _("No hostname defined for the dictionary server")((char *) g_dgettext ("cafe-utils", "No hostname defined for the dictionary server"
))
);
1879
1880 return FALSE(0);
1881 }
1882
1883 /* forgive the absence of a port */
1884 if (!priv->port)
1885 priv->port = GDICT_DEFAULT_PORT2628;
1886
1887 priv->is_connecting = TRUE(!(0));
1888
1889 lookup_error = NULL((void*)0);
1890 res = gdict_client_context_lookup_server (context, &lookup_error);
1891 if (!res)
1892 {
1893 g_propagate_error (error, lookup_error);
1894
1895 return FALSE(0);
1896 }
1897
1898#ifdef ENABLE_IPV61
1899 if (priv->sockaddr.ss_family == AF_INET610)
1900 ((struct sockaddr_in6 *) &priv->sockaddr)->sin6_port = g_htons (priv->port)(((((guint16) ( (guint16) ((guint16) (priv->port) >>
8) | (guint16) ((guint16) (priv->port) << 8))))))
;
1901 else
1902#endif
1903 ((struct sockaddr_in *) &priv->sockaddr)->sin_port = g_htons (priv->port)(((((guint16) ( (guint16) ((guint16) (priv->port) >>
8) | (guint16) ((guint16) (priv->port) << 8))))))
;
1904
1905
1906#ifdef ENABLE_IPV61
1907 if (priv->sockaddr.ss_family == AF_INET610)
1908 {
1909 sock_fd = socket (AF_INET610, SOCK_STREAMSOCK_STREAM, 0);
1910 if (sock_fd < 0)
1911 {
1912 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1913 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1914 _("Unable to create socket")((char *) g_dgettext ("cafe-utils", "Unable to create socket"
))
);
1915
1916 return FALSE(0);
1917 }
1918
1919 addrlen = sizeof (struct sockaddr_in6);
1920 }
1921 else
1922 {
1923#endif /* ENABLE_IPV6 */
1924 sock_fd = socket (AF_INET2, SOCK_STREAMSOCK_STREAM, 0);
1925 if (sock_fd < 0)
1926 {
1927 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1928 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1929 _("Unable to create socket")((char *) g_dgettext ("cafe-utils", "Unable to create socket"
))
);
1930
1931 return FALSE(0);
1932 }
1933
1934 addrlen = sizeof (struct sockaddr_in);
1935#ifdef ENABLE_IPV61
1936 }
1937#endif
1938
1939 priv->channel = g_io_channel_unix_new (sock_fd);
1940
1941 /* RFC2229 mandates the usage of UTF-8, so we force this encoding */
1942 g_io_channel_set_encoding (priv->channel, "UTF-8", NULL((void*)0));
1943
1944 g_io_channel_set_line_term (priv->channel, "\r\n", 2);
1945
1946 /* make sure that the channel is non-blocking */
1947 flags = g_io_channel_get_flags (priv->channel);
1948 flags |= G_IO_FLAG_NONBLOCK;
1949 flags_error = NULL((void*)0);
1950 g_io_channel_set_flags (priv->channel, flags, &flags_error);
1951 if (flags_error)
1952 {
1953 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1954 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1955 _("Unable to set the channel as non-blocking: %s")((char *) g_dgettext ("cafe-utils", "Unable to set the channel as non-blocking: %s"
))
,
1956 flags_error->message);
1957
1958 g_error_free (flags_error);
1959 g_io_channel_unref (priv->channel);
1960
1961 return FALSE(0);
1962 }
1963
1964 /* let the magic begin */
1965 sock_res = connect (sock_fd, (struct sockaddr *) &priv->sockaddr, addrlen);
1966 if ((sock_res != 0) && (errno(*__errno_location ()) != EINPROGRESS115))
1967 {
1968 g_set_error (error, GDICT_CLIENT_CONTEXT_ERROR(gdict_client_context_error_quark ()),
1969 GDICT_CLIENT_CONTEXT_ERROR_SOCKET,
1970 _("Unable to connect to the dictionary server at '%s:%d'")((char *) g_dgettext ("cafe-utils", "Unable to connect to the dictionary server at '%s:%d'"
))
,
1971 priv->hostname,
1972 priv->port);
1973
1974 return FALSE(0);
1975 }
1976
1977 priv->timeout_id = g_timeout_add_seconds (CONNECTION_TIMEOUT_SEC30,
1978 check_for_connection,
1979 context);
1980
1981 /* XXX - remember that g_io_add_watch() increases the reference count
1982 * of the GIOChannel we are using.
1983 */
1984 priv->source_id = g_io_add_watch (priv->channel,
1985 (G_IO_IN | G_IO_ERR),
1986 (GIOFunc) gdict_client_context_io_watch_cb,
1987 context);
1988
1989 return TRUE(!(0));
1990}
1991
1992static void
1993gdict_client_context_disconnect (GdictClientContext *context)
1994{
1995 GdictCommand *cmd;
1996
1997 g_return_if_fail (GDICT_IS_CLIENT_CONTEXT (context))do{ (void)0; }while (0);
1998
1999 /* instead of just breaking the connection to the server, we push
2000 * a QUIT command on the queue, and wait for every other scheduled
2001 * command to perform; this allows the creation of a batch of
2002 * commands.
2003 */
2004 cmd = gdict_command_new (CMD_QUIT);
2005 cmd->state = S_FINISH;
2006
2007 gdict_client_context_push_command (context, cmd);
2008}
2009
2010static gboolean
2011gdict_client_context_is_connected (GdictClientContext *context)
2012{
2013 g_assert (GDICT_IS_CLIENT_CONTEXT (context))do { (void) 0; } while (0);
2014
2015 /* we are in the middle of a connection attempt */
2016 if (context->priv->is_connecting)
2017 return TRUE(!(0));
2018
2019 return (context->priv->channel != NULL((void*)0) && context->priv->source_id != 0);
2020}
2021
2022static gboolean
2023gdict_client_context_get_databases (GdictContext *context,
2024 GError **error)
2025{
2026 GdictClientContext *client_ctx;
2027 GdictCommand *cmd;
2028
2029 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), FALSE)do{ (void)0; }while (0);
2030
2031 client_ctx = GDICT_CLIENT_CONTEXT (context)((((GdictClientContext*) (void *) ((context)))));
2032
2033 g_signal_emit_by_name (context, "lookup-start");
2034
2035 if (!gdict_client_context_is_connected (client_ctx))
2036 {
2037 GError *connect_error = NULL((void*)0);
2038
2039 gdict_client_context_connect (client_ctx, &connect_error);
2040 if (connect_error)
2041 {
2042 g_signal_emit_by_name (context, "lookup-end");
2043
2044 g_propagate_error (error, connect_error);
2045
2046 return FALSE(0);
2047 }
2048 }
2049
2050 cmd = gdict_command_new (CMD_SHOW_DB);
2051
2052 return gdict_client_context_push_command (client_ctx, cmd);
2053}
2054
2055static gboolean
2056gdict_client_context_get_strategies (GdictContext *context,
2057 GError **error)
2058{
2059 GdictClientContext *client_ctx;
2060 GdictCommand *cmd;
2061
2062 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), FALSE)do{ (void)0; }while (0);
2063
2064 client_ctx = GDICT_CLIENT_CONTEXT (context)((((GdictClientContext*) (void *) ((context)))));
2065
2066 g_signal_emit_by_name (context, "lookup-start");
2067
2068 if (!gdict_client_context_is_connected (client_ctx))
2069 {
2070 GError *connect_error = NULL((void*)0);
2071
2072 gdict_client_context_connect (client_ctx, &connect_error);
2073 if (connect_error)
2074 {
2075 g_signal_emit_by_name (context, "lookup-end");
2076
2077 g_propagate_error (error, connect_error);
2078
2079 return FALSE(0);
2080 }
2081 }
2082
2083 cmd = gdict_command_new (CMD_SHOW_STRAT);
2084
2085 return gdict_client_context_push_command (client_ctx, cmd);
2086}
2087
2088static gboolean
2089gdict_client_context_define_word (GdictContext *context,
2090 const gchar *database,
2091 const gchar *word,
2092 GError **error)
2093{
2094 GdictClientContext *client_ctx;
2095 GdictCommand *cmd;
2096
2097 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), FALSE)do{ (void)0; }while (0);
2098
2099 client_ctx = GDICT_CLIENT_CONTEXT (context)((((GdictClientContext*) (void *) ((context)))));
2100
2101 g_signal_emit_by_name (context, "lookup-start");
2102
2103 if (!gdict_client_context_is_connected (client_ctx))
2104 {
2105 GError *connect_error = NULL((void*)0);
2106
2107 gdict_client_context_connect (client_ctx, &connect_error);
2108 if (connect_error)
2109 {
2110 g_signal_emit_by_name (context, "lookup-end");
2111
2112 g_propagate_error (error, connect_error);
2113
2114 return FALSE(0);
2115 }
2116 }
2117
2118 cmd = gdict_command_new (CMD_DEFINE);
2119 cmd->database = g_strdup ((database != NULL ? database : GDICT_DEFAULT_DATABASE))g_strdup_inline ((database != ((void*)0) ? database : "*"));
2120 cmd->word = g_utf8_normalize (word, -1, G_NORMALIZE_NFC);
2121
2122 return gdict_client_context_push_command (client_ctx, cmd);
2123}
2124
2125static gboolean
2126gdict_client_context_match_word (GdictContext *context,
2127 const gchar *database,
2128 const gchar *strategy,
2129 const gchar *word,
2130 GError **error)
2131{
2132 GdictClientContext *client_ctx;
2133 GdictCommand *cmd;
2134
2135 g_return_val_if_fail (GDICT_IS_CLIENT_CONTEXT (context), FALSE)do{ (void)0; }while (0);
2136
2137 client_ctx = GDICT_CLIENT_CONTEXT (context)((((GdictClientContext*) (void *) ((context)))));
2138
2139 g_signal_emit_by_name (context, "lookup-start");
2140
2141 if (!gdict_client_context_is_connected (client_ctx))
2142 {
2143 GError *connect_error = NULL((void*)0);
2144
2145 gdict_client_context_connect (client_ctx, &connect_error);
2146 if (connect_error)
2147 {
2148 g_signal_emit_by_name (context, "lookup-end");
2149
2150 g_propagate_error (error, connect_error);
2151
2152 return FALSE(0);
2153 }
2154 }
2155
2156 cmd = gdict_command_new (CMD_MATCH);
2157 cmd->database = g_strdup ((database != NULL ? database : GDICT_DEFAULT_DATABASE))g_strdup_inline ((database != ((void*)0) ? database : "*"));
2158 cmd->strategy = g_strdup ((strategy != NULL ? strategy : GDICT_DEFAULT_STRATEGY))g_strdup_inline ((strategy != ((void*)0) ? strategy : "."));
2159 cmd->word = g_utf8_normalize (word, -1, G_NORMALIZE_NFC);
2160
2161 return gdict_client_context_push_command (client_ctx, cmd);
2162}