From e782f9dad3b7ab11e37a3feea17a9fa2b9841d29 Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Fri, 23 Feb 2024 17:44:39 +0000 Subject: Deploy mate-desktop/mate-utils to github.com/mate-desktop/mate-utils.git:gh-pages --- .../index.html | 151 + .../report-067bf0.html | 2047 +++++++++++ .../report-1f8d97.html | 2893 ++++++++++++++++ .../report-39d028.html | 2833 +++++++++++++++ .../report-672223.html | 2888 ++++++++++++++++ .../report-777170.html | 2893 ++++++++++++++++ .../report-783b4f.html | 2000 +++++++++++ .../report-91f89a.html | 2007 +++++++++++ .../report-9aacf9.html | 2047 +++++++++++ .../report-ace5d0.html | 2833 +++++++++++++++ .../report-b62710.html | 2878 +++++++++++++++ .../report-b8f564.html | 2089 +++++++++++ .../report-bafe5d.html | 3648 ++++++++++++++++++++ .../report-bcdee0.html | 2893 ++++++++++++++++ .../report-cf3974.html | 2089 +++++++++++ .../report-d66062.html | 2119 ++++++++++++ .../report-e4b97b.html | 3640 +++++++++++++++++++ .../report-ee3f8f.html | 954 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ 20 files changed, 43456 insertions(+) create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/index.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-067bf0.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-1f8d97.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-39d028.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-672223.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-777170.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-783b4f.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-91f89a.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-9aacf9.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-ace5d0.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-b62710.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-b8f564.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-bafe5d.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-bcdee0.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-cf3974.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-d66062.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-e4b97b.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/report-ee3f8f.html create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/scanview.css create mode 100644 2023-09-19-105706-7102-1@63a29bff1e50_master/sorttable.js (limited to '2023-09-19-105706-7102-1@63a29bff1e50_master') diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/index.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/index.html new file mode 100644 index 00000000..23c0635e --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/index.html @@ -0,0 +1,151 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@cf9f68b25e34
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 16.0.6 (Fedora 16.0.6-3.fc38) +
Date:Tue Sep 19 10:57:06 2023
+

Bug Summary

+ + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs17
API
Argument with 'nonnull' attribute passed null1
Logic error
Cast from non-struct type to struct type2
Dereference of null pointer4
Out-of-bound access2
Result of operation is garbage or undefined1
Uninitialized argument value1
Unused code
Dead increment1
Unreachable code5
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
APIArgument with 'nonnull' attribute passed nullmate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line148117View Report
Logic errorCast from non-struct type to struct typegsearchtool/mate-submodules/libegg/eggsmclient-xsmp.carray_prop11991View Report
Logic errorCast from non-struct type to struct typegsearchtool/mate-submodules/libegg/eggsmclient-xsmp.cptrarray_prop12321View Report
Unused codeDead incrementmate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line13791View Report
Logic errorDereference of null pointermate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line161022View Report
Logic errorDereference of null pointermate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line150421View Report
Logic errorDereference of null pointermate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line145022View Report
Logic errorDereference of null pointermate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line140322View Report
Logic errorOut-of-bound accessmate-screenshot/src/mate-screenshot.cbuild_uri92525View Report
Logic errorOut-of-bound accessmate-dictionary/libgdict/gdict-defbox.cbreakup_string86524View Report
Logic errorResult of operation is garbage or undefinedmate-dictionary/libgdict/gdict-defbox.clines_match62927View Report
Logic errorUninitialized argument valuemate-dictionary/src/gdict-applet.cset_window_default_size1599View Report
Unused codeUnreachable codemate-screenshot/src/mate-screenshot.cmain13261View Report
Unused codeUnreachable codemate-dictionary/libgdict/gdict-client-context.cgdict_client_context_parse_line13971View Report
Unused codeUnreachable codebaobab/src/baobab.cshow_version12161View Report
Unused codeUnreachable codemate-screenshot/src/mate-screenshot.cmain13621View Report
Unused codeUnreachable codemate-screenshot/src/screenshot-save.cscreenshot_save_start2271View Report
+ + diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-067bf0.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-067bf0.html new file mode 100644 index 00000000..4d7c6f69 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-067bf0.html @@ -0,0 +1,2047 @@ + + + +mate-screenshot.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-screenshot/src/mate-screenshot.c
Warning:line 1326, column 26
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-screenshot.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 static -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/mate-screenshot/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I . -I . -D MATELOCALEDIR="/usr/local/share/locale" -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -D _REENTRANT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-screenshot/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c mate-screenshot.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
2 * Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
3 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
4 * Copyright (C) 2012-2021 MATE Developers
5 *
6 * This file is part of MATE Utils.
7 *
8 * MATE Utils is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * MATE Utils is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#ifdef HAVE_CONFIG_H1
23#include <config.h>
24#endif
25
26#include <gdk/gdkx.h>
27#include <gdk/gdkkeysyms.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <errno(*__errno_location ()).h>
35#ifdef ENABLE_NLS1
36#include <locale.h>
37#endif /* ENABLE_NLS */
38#include <glib/gi18n.h>
39#include <gio/gio.h>
40#include <pwd.h>
41#include <X11/Xutil.h>
42#include <canberra-gtk.h>
43
44#include "screenshot-shadow.h"
45#include "screenshot-utils.h"
46#include "screenshot-save.h"
47#include "screenshot-dialog.h"
48#include "screenshot-xfer.h"
49
50#define SCREENSHOOTER_ICON"applets-screenshooter" "applets-screenshooter"
51
52#define MATE_SCREENSHOT_SCHEMA"org.mate.screenshot" "org.mate.screenshot"
53#define INCLUDE_BORDER_KEY"include-border" "include-border"
54#define INCLUDE_POINTER_KEY"include-pointer" "include-pointer"
55#define LAST_SAVE_DIRECTORY_KEY"last-save-directory" "last-save-directory"
56#define BORDER_EFFECT_KEY"border-effect" "border-effect"
57#define DELAY_KEY"delay" "delay"
58#define CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences" "org.mate.caja.preferences"
59
60enum
61{
62 COLUMN_NICK,
63 COLUMN_LABEL,
64 COLUMN_ID,
65
66 N_COLUMNS
67};
68
69typedef enum {
70 SCREENSHOT_EFFECT_NONE,
71 SCREENSHOT_EFFECT_SHADOW,
72 SCREENSHOT_EFFECT_BORDER
73} ScreenshotEffectType;
74
75typedef enum
76{
77 TEST_LAST_DIR = 0,
78 TEST_DESKTOP = 1,
79 TEST_TMP = 2,
80} TestType;
81
82typedef struct
83{
84 char *base_uris[3];
85 char *retval;
86 int iteration;
87 TestType type;
88 GdkWindow *window;
89 GdkRectangle *rectangle;
90} AsyncExistenceJob;
91
92static GdkPixbuf *screenshot = NULL((void*)0);
93
94/* Global variables*/
95static char *last_save_dir = NULL((void*)0);
96static char *temporary_file = NULL((void*)0);
97static gboolean save_immediately = FALSE(0);
98static GSettings *settings = NULL((void*)0);
99static gboolean interactive_arg = FALSE(0);
100static guint delay_arg = 0;
101
102/* Options */
103static gboolean noninteractive_clipboard_arg = FALSE(0);
104static gboolean take_window_shot = FALSE(0);
105static gboolean take_area_shot = FALSE(0);
106static gboolean include_border = FALSE(0);
107static gboolean include_pointer = TRUE(!(0));
108static char *border_effect = NULL((void*)0);
109static guint delay = 0;
110
111/* some local prototypes */
112static void display_help (GtkWindow *parent);
113static void save_done_notification (gpointer data);
114static char *get_desktop_dir (void);
115static void save_options (void);
116
117static GtkWidget *border_check = NULL((void*)0);
118static GtkWidget *effect_combo = NULL((void*)0);
119static GtkWidget *effect_label = NULL((void*)0);
120static GtkWidget *effects_vbox = NULL((void*)0);
121static GtkWidget *delay_hbox = NULL((void*)0);
122
123void loop_dialog_screenshot (void);
124
125static void
126display_help (GtkWindow *parent)
127{
128 GError *error = NULL((void*)0);
129
130 gtk_show_uri_on_window (parent,
131 "help:mate-user-guide/goseditmainmenu-53",
132 gtk_get_current_event_time (),
133 &error);
134
135 if (error)
136 {
137 screenshot_show_gerror_dialog (parent,
138 _("Error loading the help page")gettext ("Error loading the help page"),
139 error);
140 g_error_free (error);
141 }
142}
143
144static void
145interactive_dialog_response_cb (GtkDialog *dialog,
146 gint response,
147 gpointer user_data)
148{
149 switch (response)
150 {
151 case GTK_RESPONSE_HELP:
152 g_signal_stop_emission_by_name (dialog, "response");
153 display_help (GTK_WINDOW (dialog)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_window_get_type ()))))))
);
154 break;
155 default:
156 gtk_widget_hide (GTK_WIDGET (dialog)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_widget_get_type ()))))))
);
157 break;
158 }
159}
160
161#define TARGET_TOGGLE_DESKTOP0 0
162#define TARGET_TOGGLE_WINDOW1 1
163#define TARGET_TOGGLE_AREA2 2
164
165static void
166target_toggled_cb (GtkToggleButton *button,
167 gpointer data)
168{
169 int target_toggle = GPOINTER_TO_INT (data)((gint) (glong) (data));
170
171 if (gtk_toggle_button_get_active (button))
172 {
173 take_window_shot = (target_toggle == TARGET_TOGGLE_WINDOW1);
174 take_area_shot = (target_toggle == TARGET_TOGGLE_AREA2);
175
176 gtk_widget_set_sensitive (border_check, take_window_shot);
177 gtk_widget_set_sensitive (effect_combo, take_window_shot);
178 gtk_widget_set_sensitive (effect_label, take_window_shot);
179
180 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
181 gtk_widget_set_sensitive (effects_vbox, !take_area_shot);
182 }
183}
184
185static void
186delay_spin_value_changed_cb (GtkSpinButton *button)
187{
188 delay = gtk_spin_button_get_value_as_int (button);
189}
190
191static void
192include_border_toggled_cb (GtkToggleButton *button,
193 gpointer data)
194{
195 include_border = gtk_toggle_button_get_active (button);
196}
197
198static void
199include_pointer_toggled_cb (GtkToggleButton *button,
200 gpointer data)
201{
202 include_pointer = gtk_toggle_button_get_active (button);
203}
204
205static void
206effect_combo_changed_cb (GtkComboBox *combo,
207 gpointer user_data)
208{
209 GtkTreeIter iter;
210
211 if (gtk_combo_box_get_active_iter (combo, &iter))
212 {
213 GtkTreeModel *model;
214 gchar *effect;
215
216 model = gtk_combo_box_get_model (combo);
217 gtk_tree_model_get (model, &iter, COLUMN_NICK, &effect, -1);
218
219 g_assert (effect != NULL)do { if (effect != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "mate-screenshot.c", 219, ((const char*) (__func__
)), "effect != NULL"); } while (0)
;
220
221 g_free (border_effect);
222 border_effect = effect; /* gets free'd later */
223 }
224}
225
226static gint
227key_press_cb (GtkWidget* widget, GdkEventKey* event, gpointer data)
228{
229 if (event->keyval == GDK_KEY_F10xffbe)
230 {
231 display_help (GTK_WINDOW (widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gtk_window_get_type ()))))))
);
232 return TRUE(!(0));
233 }
234
235 return FALSE(0);
236}
237
238typedef struct {
239 ScreenshotEffectType id;
240 const gchar *label;
241 const gchar *nick;
242} ScreenshotEffect;
243
244/* Translators:
245 * these are the names of the effects available which will be
246 * displayed inside a combo box in interactive mode for the user
247 * to chooser.
248 */
249static const ScreenshotEffect effects[] = {
250 { SCREENSHOT_EFFECT_NONE, N_("None")("None"), "none" },
251 { SCREENSHOT_EFFECT_SHADOW, N_("Drop shadow")("Drop shadow"), "shadow" },
252 { SCREENSHOT_EFFECT_BORDER, N_("Border")("Border"), "border" }
253};
254
255static guint n_effects = G_N_ELEMENTS (effects)(sizeof (effects) / sizeof ((effects)[0]));
256
257static GtkWidget *
258create_effects_combo (void)
259{
260 GtkWidget *retval;
261 GtkListStore *model;
262 GtkCellRenderer *renderer;
263 gint i;
264
265 model = gtk_list_store_new (N_COLUMNS,
266 G_TYPE_STRING((GType) ((16) << (2))),
267 G_TYPE_STRING((GType) ((16) << (2))),
268 G_TYPE_UINT((GType) ((7) << (2))));
269
270 for (i = 0; i < n_effects; i++)
271 {
272 GtkTreeIter iter;
273
274 gtk_list_store_insert (model, &iter, i);
275 gtk_list_store_set (model, &iter,
276 COLUMN_ID, effects[i].id,
277 COLUMN_LABEL, gettext (effects[i].label),
278 COLUMN_NICK, effects[i].nick,
279 -1);
280 }
281
282 retval = gtk_combo_box_new ();
283 gtk_combo_box_set_model (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
284 GTK_TREE_MODEL (model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((gtk_tree_model_get_type ()))))))
);
285 g_object_unref (model);
286
287 switch (border_effect[0])
288 {
289 case 's': /* shadow */
290 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
291 SCREENSHOT_EFFECT_SHADOW);
292 break;
293 case 'b': /* border */
294 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
295 SCREENSHOT_EFFECT_BORDER);
296 break;
297 case 'n': /* none */
298 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
299 SCREENSHOT_EFFECT_NONE);
300 break;
301 default:
302 break;
303 }
304
305 renderer = gtk_cell_renderer_text_new ();
306 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer, TRUE(!(0)));
307 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer,
308 "text", COLUMN_LABEL,
309 NULL((void*)0));
310
311 g_signal_connect (retval, "changed",g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
312 G_CALLBACK (effect_combo_changed_cb),g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
313 NULL)g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
314
315 return retval;
316}
317
318static void
319create_effects_frame (GtkWidget *outer_vbox,
320 const gchar *frame_title)
321{
322 GtkWidget *main_vbox, *vbox, *hbox;
323 GtkWidget *label;
324 GtkWidget *check;
325 GtkWidget *combo;
326 gchar *title;
327
328 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
329 gtk_widget_set_sensitive (main_vbox, !take_area_shot);
330 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
331 gtk_widget_show (main_vbox);
332 effects_vbox = main_vbox;
333
334 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
335 label = gtk_label_new (title);
336 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
337 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
338 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
339 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
340 gtk_widget_show (label);
341 g_free (title);
342
343 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
344 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
345 gtk_widget_show (hbox);
346
347 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
348 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
349 gtk_widget_set_margin_start (vbox, 12);
350 gtk_widget_show (vbox);
351
352 /** Include pointer **/
353 check = gtk_check_button_new_with_mnemonic (_("Include _pointer")gettext ("Include _pointer"));
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_pointer);
355 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
356 G_CALLBACK (include_pointer_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
357 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
358 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
359 gtk_widget_show (check);
360
361 /** Include window border **/
362 check = gtk_check_button_new_with_mnemonic (_("Include the window _border")gettext ("Include the window _border"));
363 gtk_widget_set_sensitive (check, take_window_shot);
364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_border);
365 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
366 G_CALLBACK (include_border_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
367 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
368 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
369 gtk_widget_show (check);
370 border_check = check;
371
372 /** Effects **/
373 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
374 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
375 gtk_widget_show (hbox);
376
377 label = gtk_label_new_with_mnemonic (_("Apply _effect:")gettext ("Apply _effect:"));
378 gtk_widget_set_sensitive (label, take_window_shot);
379 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
380 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
381 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
382 gtk_widget_show (label);
383 effect_label = label;
384
385 combo = create_effects_combo ();
386 gtk_widget_set_sensitive (combo, take_window_shot);
387 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, combo, FALSE(0), FALSE(0), 0);
388 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, combo);
389 gtk_widget_show (combo);
390 effect_combo = combo;
391}
392
393static void
394create_screenshot_frame (GtkWidget *outer_vbox,
395 const gchar *frame_title)
396{
397 GtkWidget *main_vbox, *vbox, *hbox;
398 GtkWidget *radio;
399 GtkWidget *image;
400 GtkWidget *spin;
401 GtkWidget *label;
402 GtkAdjustment *adjust;
403 GSList *group;
404 gchar *title;
405
406 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
407 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
408 gtk_widget_show (main_vbox);
409
410 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
411 label = gtk_label_new (title);
412 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
413 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
414 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
415 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
416 gtk_widget_show (label);
417 g_free (title);
418
419 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
420 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
421 gtk_widget_show (hbox);
422
423 image = gtk_image_new_from_icon_name (SCREENSHOOTER_ICON"applets-screenshooter",
424 GTK_ICON_SIZE_DIALOG);
425
426 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image, FALSE(0), FALSE(0), 0);
427 gtk_widget_set_valign (image, GTK_ALIGN_START);
428 gtk_widget_show (image);
429
430 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
431 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
432 gtk_widget_show (vbox);
433
434 /** Grab whole desktop **/
435 group = NULL((void*)0);
436 radio = gtk_radio_button_new_with_mnemonic (group,
437 _("Grab the whole _desktop")gettext ("Grab the whole _desktop"));
438 if (take_window_shot || take_area_shot)
439 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, FALSE(0));
440 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
441 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
442 GINT_TO_POINTER (TARGET_TOGGLE_DESKTOP))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
;
443 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
444 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
445 gtk_widget_show (radio);
446
447 /** Grab current window **/
448 radio = gtk_radio_button_new_with_mnemonic (group,
449 _("Grab the current _window")gettext ("Grab the current _window"));
450 if (take_window_shot)
451 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
452 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
453 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
454 GINT_TO_POINTER (TARGET_TOGGLE_WINDOW))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
;
455 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
456 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
457 gtk_widget_show (radio);
458
459 /** Grab area of the desktop **/
460 radio = gtk_radio_button_new_with_mnemonic (group,
461 _("Select _area to grab")gettext ("Select _area to grab"));
462 if (take_area_shot)
463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
464 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
465 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
466 GINT_TO_POINTER (TARGET_TOGGLE_AREA))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
;
467 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
468 gtk_widget_show (radio);
469
470 /** Grab after delay **/
471 delay_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
472 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
473 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, delay_hbox, FALSE(0), FALSE(0), 0);
474 gtk_widget_show (delay_hbox);
475
476 /* translators: this is the first part of the "grab after a
477 * delay of <spin button> seconds".
478 */
479 label = gtk_label_new_with_mnemonic (_("Grab _after a delay of")gettext ("Grab _after a delay of"));
480 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
481 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
482 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
483 gtk_widget_show (label);
484
485 adjust = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) delay,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
486 0.0, 99.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
487 1.0, 1.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
488 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
;
489 spin = gtk_spin_button_new (adjust, 1.0, 0);
490 g_signal_connect (spin, "value-changed",g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
491 G_CALLBACK (delay_spin_value_changed_cb),g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
492 NULL)g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
493 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, spin, FALSE(0), FALSE(0), 0);
494 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, spin);
495 gtk_widget_show (spin);
496
497 /* translators: this is the last part of the "grab after a
498 * delay of <spin button> seconds".
499 */
500 label = gtk_label_new (_("seconds")gettext ("seconds"));
501 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
502 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
503 gtk_box_pack_end (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
504 gtk_widget_show (label);
505}
506
507static GtkWidget *
508create_interactive_dialog (void)
509{
510 GtkWidget *retval;
511 GtkWidget *main_vbox;
512 GtkWidget *content_area;
513
514 retval = gtk_dialog_new ();
515 gtk_window_set_resizable (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, FALSE(0));
516 gtk_container_set_border_width (GTK_CONTAINER (retval)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_container_get_type ()))))))
, 5);
517 content_area = gtk_dialog_get_content_area (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
);
518 gtk_box_set_spacing (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, 2);
519 gtk_window_set_title (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, _("Take Screenshot")gettext ("Take Screenshot"));
520
521 /* main container */
522 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
523 gtk_container_set_border_width (GTK_CONTAINER (main_vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_container_get_type ()))))))
, 5);
524 gtk_box_pack_start (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, main_vbox, TRUE(!(0)), TRUE(!(0)), 0);
525 gtk_widget_show (main_vbox);
526
527 create_screenshot_frame (main_vbox, _("Take Screenshot")gettext ("Take Screenshot"));
528 create_effects_frame (main_vbox, _("Effects")gettext ("Effects"));
529 gtk_dialog_add_buttons (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
,
530 "gtk-help", GTK_RESPONSE_HELP,
531 "gtk-cancel", GTK_RESPONSE_CANCEL,
532 _("Take _Screenshot")gettext ("Take _Screenshot"), GTK_RESPONSE_OK,
533 NULL((void*)0));
534 gtk_dialog_set_default_response (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
535
536 /* we need to block on "response" and keep showing the interactive
537 * dialog in case the user did choose "help"
538 */
539 g_signal_connect (retval, "response",g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
540 G_CALLBACK (interactive_dialog_response_cb),g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
541 NULL)g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
542
543 g_signal_connect (retval, "key-press-event",g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
544 G_CALLBACK(key_press_cb),g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
545 NULL)g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
546
547 return retval;
548}
549
550static void
551save_folder_to_settings (ScreenshotDialog *dialog)
552{
553 char *folder;
554
555 folder = screenshot_dialog_get_folder (dialog);
556 g_settings_set_string (settings,
557 LAST_SAVE_DIRECTORY_KEY"last-save-directory", folder);
558
559 g_free (folder);
560}
561
562static void
563set_recent_entry (ScreenshotDialog *dialog)
564{
565 char *uri, *app_exec = NULL((void*)0);
566 GtkRecentManager *recent;
567 GtkRecentData recent_data;
568 GAppInfo *app;
569 const char *exec_name = NULL((void*)0);
570 static char * groups[2] = { "Graphics", NULL((void*)0) };
571
572 app = g_app_info_get_default_for_type ("image/png", TRUE(!(0)));
573
574 if (!app) {
575 /* return early, as this would be an useless recent entry anyway. */
576 return;
577 }
578
579 uri = screenshot_dialog_get_uri (dialog);
580 recent = gtk_recent_manager_get_default ();
581
582 exec_name = g_app_info_get_executable (app);
583 app_exec = g_strjoin (" ", exec_name, "%u", NULL((void*)0));
584
585 recent_data.display_name = NULL((void*)0);
586 recent_data.description = NULL((void*)0);
587 recent_data.mime_type = "image/png";
588 recent_data.app_name = "MATE Screenshot";
589 recent_data.app_exec = app_exec;
590 recent_data.groups = groups;
591 recent_data.is_private = FALSE(0);
592
593 gtk_recent_manager_add_full (recent, uri, &recent_data);
594
595 g_object_unref (app);
596 g_free (app_exec);
597 g_free (uri);
598}
599
600static void
601error_dialog_response_cb (GtkDialog *d,
602 gint response,
603 ScreenshotDialog *dialog)
604{
605 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
606
607 screenshot_dialog_focus_entry (dialog);
608}
609
610static void
611save_callback (TransferResult result,
612 char *error_message,
613 gpointer data)
614{
615 ScreenshotDialog *dialog = data;
616 GtkWidget *toplevel;
617
618 toplevel = screenshot_dialog_get_toplevel (dialog);
619 screenshot_dialog_set_busy (dialog, FALSE(0));
620
621 if (result == TRANSFER_OK)
622 {
623 save_folder_to_settings (dialog);
624 set_recent_entry (dialog);
625 gtk_widget_destroy (toplevel);
626
627 /* we're done, stop the mainloop now */
628 gtk_main_quit ();
629 }
630 else if (result == TRANSFER_OVERWRITE ||
631 result == TRANSFER_CANCELLED)
632 {
633 /* user has canceled the overwrite dialog or the transfer itself, let him
634 * choose another name.
635 */
636 screenshot_dialog_focus_entry (dialog);
637 }
638 else /* result == TRANSFER_ERROR */
639 {
640 /* we had an error, display a dialog to the user and let him choose
641 * another name/location to save the screenshot.
642 */
643 GtkWidget *error_dialog;
644 char *uri;
645
646 uri = screenshot_dialog_get_uri (dialog);
647 error_dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_window_get_type ()))))))
,
648 GTK_DIALOG_DESTROY_WITH_PARENT,
649 GTK_MESSAGE_ERROR,
650 GTK_BUTTONS_OK,
651 _("Error while saving screenshot")gettext ("Error while saving screenshot"));
652 /* translators: first %s is the file path, second %s is the VFS error */
653 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog)((((GtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((error_dialog)), ((gtk_message_dialog_get_type
()))))))
,
654 _("Impossible to save the screenshot "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
655 "to %s.\n Error was %s.\n Please choose another "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
656 "location and retry.")gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
, uri, error_message);
657 gtk_widget_show (error_dialog);
658 g_signal_connect (error_dialog,g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
659 "response",g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
660 G_CALLBACK (error_dialog_response_cb),g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
661 dialog)g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
662
663 g_free (uri);
664 }
665
666}
667
668static void
669try_to_save (ScreenshotDialog *dialog,
670 const char *target)
671{
672 GFile *source_file, *target_file;
673
674 g_assert (temporary_file)do { if (temporary_file) ; else g_assertion_message_expr (((gchar
*) 0), "mate-screenshot.c", 674, ((const char*) (__func__)), "temporary_file"
); } while (0)
;
675
676 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
677
678 source_file = g_file_new_for_path (temporary_file);
679 target_file = g_file_new_for_uri (target);
680
681 screenshot_xfer_uri (source_file,
682 target_file,
683 screenshot_dialog_get_toplevel (dialog),
684 save_callback, dialog);
685
686 /* screenshot_xfer_uri () holds a ref, so we can unref now */
687 g_object_unref (source_file);
688 g_object_unref (target_file);
689}
690
691static void
692save_done_notification (gpointer data)
693{
694 ScreenshotDialog *dialog = data;
695
696 temporary_file = g_strdup (screenshot_save_get_filename ())g_strdup_inline (screenshot_save_get_filename ());
697 screenshot_dialog_enable_dnd (dialog);
698
699 if (save_immediately)
700 {
701 GtkWidget *toplevel;
702
703 toplevel = screenshot_dialog_get_toplevel (dialog);
704 gtk_dialog_response (GTK_DIALOG (toplevel)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
705 }
706}
707
708static void
709save_screenshot_in_clipboard (GdkDisplay *display, GdkPixbuf *screenshot)
710{
711 GtkClipboard *clipboard =
712 gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
713 gtk_clipboard_set_image (clipboard, screenshot);
714}
715
716static void
717screenshot_dialog_response_cb (GtkDialog *d,
718 gint response_id,
719 ScreenshotDialog *dialog)
720{
721 char *uri;
722
723 if (response_id == GTK_RESPONSE_HELP)
724 {
725 display_help (GTK_WINDOW (d)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_window_get_type ()))))))
);
726 }
727 else if (response_id == SCREENSHOT_RESPONSE_NEW22)
728 {
729 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
730 gtk_main_quit ();
731 interactive_arg = TRUE(!(0));
732 loop_dialog_screenshot();
733 }
734 else if (response_id == GTK_RESPONSE_OK)
735 {
736 uri = screenshot_dialog_get_uri (dialog);
737 if (temporary_file == NULL((void*)0))
738 {
739 save_immediately = TRUE(!(0));
740 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
741 }
742 else
743 {
744 /* we've saved the temporary file, lets try to copy it to the
745 * correct location.
746 */
747 try_to_save (dialog, uri);
748 }
749 g_free (uri);
750 }
751 else if (response_id == SCREENSHOT_RESPONSE_COPY1)
752 {
753 save_screenshot_in_clipboard (gtk_widget_get_display (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
),
754 screenshot_dialog_get_screenshot (dialog));
755 }
756 else /* dialog was canceled */
757 {
758 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
759 gtk_main_quit ();
760 }
761}
762
763static void
764run_dialog (ScreenshotDialog *dialog)
765{
766 GtkWidget *toplevel;
767
768 toplevel = screenshot_dialog_get_toplevel (dialog);
769
770 gtk_widget_show (toplevel);
771
772 g_signal_connect (toplevel,g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
773 "response",g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
774 G_CALLBACK (screenshot_dialog_response_cb),g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
775 dialog)g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
776}
777
778static void
779play_sound_effect (GdkWindow *window)
780{
781 ca_context *c;
782 ca_proplist *p = NULL((void*)0);
783 int res;
784
785 c = ca_gtk_context_get ();
786
787 res = ca_proplist_create (&p);
788 if (res < 0)
789 goto done;
790
791 res = ca_proplist_sets (p, CA_PROP_EVENT_ID"event.id", "screen-capture");
792 if (res < 0)
793 goto done;
794
795 res = ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION"event.description", _("Screenshot taken")gettext ("Screenshot taken"));
796 if (res < 0)
797 goto done;
798
799 if (window != NULL((void*)0))
800 {
801 res = ca_proplist_setf (p,
802 CA_PROP_WINDOW_X11_XID"window.x11.xid",
803 "%lu",
804 (unsigned long) GDK_WINDOW_XID (window)(gdk_x11_window_get_xid (window)));
805 if (res < 0)
806 goto done;
807 }
808
809 ca_context_play_full (c, 0, p, NULL((void*)0), NULL((void*)0));
810
811 done:
812 if (p != NULL((void*)0))
813 ca_proplist_destroy (p);
814
815}
816
817static void
818finish_prepare_screenshot (char *initial_uri, GdkWindow *window, GdkRectangle *rectangle)
819{
820 ScreenshotDialog *dialog;
821 gboolean include_mask = (!take_window_shot && !take_area_shot);
822
823 /* always disable window border for full-desktop or selected-area screenshots */
824 if (!take_window_shot)
825 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, FALSE(0), include_mask);
826 else
827 {
828 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, include_border, include_mask);
829
830 switch (border_effect[0])
831 {
832 case 's': /* shadow */
833 screenshot_add_shadow (&screenshot);
834 break;
835 case 'b': /* border */
836 screenshot_add_border (&screenshot);
837 break;
838 case 'n': /* none */
839 default:
840 break;
841 }
842 }
843
844 /* release now the lock, it was acquired when we were finding the window */
845 screenshot_release_lock ();
846
847 if (screenshot == NULL((void*)0))
848 {
849 screenshot_show_error_dialog (NULL((void*)0),
850 _("Unable to take a screenshot of the current window")gettext ("Unable to take a screenshot of the current window"),
851 NULL((void*)0));
852 exit (1);
853 }
854
855 play_sound_effect (window);
856
857 if (noninteractive_clipboard_arg) {
858 save_screenshot_in_clipboard (gdk_window_get_display (window), screenshot);
859 g_free (initial_uri);
860 /* Done here: */
861 gtk_main_quit ();
862 return;
863 }
864
865 dialog = screenshot_dialog_new (screenshot, initial_uri, take_window_shot);
866 g_free (initial_uri);
867
868 screenshot_save_start (screenshot, save_done_notification, dialog);
869
870 run_dialog (dialog);
871}
872
873static void
874async_existence_job_free (AsyncExistenceJob *job)
875{
876 if (!job)
877 return;
878
879 g_free (job->base_uris[1]);
880 g_free (job->base_uris[2]);
881
882 if (job->rectangle != NULL((void*)0))
883 g_slice_free (GdkRectangle, job->rectangle)do { if (1) g_slice_free1 (sizeof (GdkRectangle), (job->rectangle
)); else (void) ((GdkRectangle*) 0 == (job->rectangle)); }
while (0)
;
884
885 g_slice_free (AsyncExistenceJob, job)do { if (1) g_slice_free1 (sizeof (AsyncExistenceJob), (job))
; else (void) ((AsyncExistenceJob*) 0 == (job)); } while (0)
;
886}
887
888static gboolean
889check_file_done (gpointer user_data)
890{
891 AsyncExistenceJob *job = user_data;
892
893 finish_prepare_screenshot (job->retval, job->window, job->rectangle);
894
895 async_existence_job_free (job);
896
897 return FALSE(0);
898}
899
900static char *
901build_uri (AsyncExistenceJob *job)
902{
903 char *retval, *file_name;
904 char *timestamp;
905 GDateTime *d;
906
907 d = g_date_time_new_now_local ();
908 timestamp = g_date_time_format (d, "%Y-%m-%d %H-%M-%S");
909 g_date_time_unref (d);
910
911 if (job->iteration == 0)
912 {
913 /* translators: this is the name of the file that gets made up
914 * with the screenshot if the entire screen is taken */
915 file_name = g_strdup_printf (_("Screenshot at %s.png")gettext ("Screenshot at %s.png"), timestamp);
916 }
917 else
918 {
919 /* translators: this is the name of the file that gets
920 * made up with the screenshot if the entire screen is
921 * taken */
922 file_name = g_strdup_printf (_("Screenshot at %s - %d.png")gettext ("Screenshot at %s - %d.png"), timestamp, job->iteration);
923 }
924
925 retval = g_build_filename (job->base_uris[job->type], file_name, NULL((void*)0));
926 g_free (file_name);
927 g_free (timestamp);
928
929 return retval;
930}
931
932static gboolean
933try_check_file (GIOSchedulerJob *io_job,
934 GCancellable *cancellable,
935 gpointer data)
936{
937 AsyncExistenceJob *job = data;
938 GFile *file;
939 GFileInfo *info;
940 GError *error;
941 char *uri;
942
943retry:
944 error = NULL((void*)0);
945 uri = build_uri (job);
946 file = g_file_new_for_uri (uri);
947
948 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
949 G_FILE_QUERY_INFO_NONE, cancellable, &error);
950 if (info != NULL((void*)0))
951 {
952 /* file already exists, iterate again */
953 g_object_unref (info);
954 g_object_unref (file);
955 g_free (uri);
956
957 (job->iteration)++;
958
959 goto retry;
960 }
961 else
962 {
963 /* see the error to check whether the location is not accessible
964 * or the file does not exist.
965 */
966 if (error->code == G_IO_ERROR_NOT_FOUND)
967 {
968 GFile *parent;
969
970 /* if the parent directory doesn't exist as well, forget the saved
971 * directory and treat this as a generic error.
972 */
973
974 parent = g_file_get_parent (file);
975
976 if (!g_file_query_exists (parent, NULL((void*)0)))
977 {
978 (job->type)++;
979 job->iteration = 0;
980
981 g_object_unref (file);
982 g_object_unref (parent);
983 goto retry;
984 }
985 else
986 {
987 job->retval = uri;
988
989 g_object_unref (parent);
990 goto out;
991 }
992 }
993 else
994 {
995 /* another kind of error, assume this location is not
996 * accessible.
997 */
998 g_free (uri);
999 if (job->type == TEST_TMP)
1000 {
1001 job->retval = NULL((void*)0);
1002 goto out;
1003 }
1004 else
1005 {
1006 (job->type)++;
1007 job->iteration = 0;
1008
1009 g_error_free (error);
1010 g_object_unref (file);
1011 goto retry;
1012 }
1013 }
1014 }
1015
1016out:
1017 g_error_free (error);
1018 g_object_unref (file);
1019
1020 g_io_scheduler_job_send_to_mainloop_async (io_job,
1021 check_file_done,
1022 job,
1023 NULL((void*)0));
1024 return FALSE(0);
1025}
1026
1027static GdkWindow *
1028find_current_window (void)
1029{
1030 GdkWindow *window;
1031
1032 if (!screenshot_grab_lock ())
1033 exit (0);
1034
1035 if (take_window_shot)
1036 {
1037 window = screenshot_find_current_window ();
1038 if (!window)
1039 {
1040 take_window_shot = FALSE(0);
1041 window = gdk_get_default_root_window ();
1042 }
1043 }
1044 else
1045 {
1046 window = gdk_get_default_root_window ();
1047 }
1048
1049 return window;
1050}
1051
1052static void
1053push_check_file_job (GdkRectangle *rectangle)
1054{
1055 AsyncExistenceJob *job;
1056
1057 job = g_slice_new0 (AsyncExistenceJob)((AsyncExistenceJob*) g_slice_alloc0 (sizeof (AsyncExistenceJob
)))
;
1058 job->base_uris[0] = last_save_dir;
1059 /* we'll have to free these two */
1060 job->base_uris[1] = get_desktop_dir ();
1061 job->base_uris[2] = g_strconcat ("file://", g_get_tmp_dir (), NULL((void*)0));
1062 job->iteration = 0;
1063 job->type = TEST_LAST_DIR;
1064 job->window = find_current_window ();
1065
1066 if (rectangle != NULL((void*)0))
1067 {
1068 job->rectangle = g_slice_new0 (GdkRectangle)((GdkRectangle*) g_slice_alloc0 (sizeof (GdkRectangle)));
1069 job->rectangle->x = rectangle->x;
1070 job->rectangle->y = rectangle->y;
1071 job->rectangle->width = rectangle->width;
1072 job->rectangle->height = rectangle->height;
1073 }
1074
1075 /* Check if the area selection was cancelled */
1076 if (job->rectangle &&
1077 (job->rectangle->width == 0 || job->rectangle->height == 0))
1078 {
1079 async_existence_job_free (job);
1080 gtk_main_quit ();
1081 return;
1082 }
1083
1084 g_io_scheduler_push_job (try_check_file,
1085 job,
1086 NULL((void*)0),
1087 0, NULL((void*)0));
1088
1089}
1090
1091static void
1092rectangle_found_cb (GdkRectangle *rectangle)
1093{
1094 push_check_file_job (rectangle);
1095}
1096
1097static void
1098prepare_screenshot (void)
1099{
1100 if (take_area_shot)
1101 screenshot_select_area_async (rectangle_found_cb);
1102 else
1103 push_check_file_job (NULL((void*)0));
1104}
1105
1106static gboolean
1107prepare_screenshot_timeout (gpointer data)
1108{
1109 prepare_screenshot ();
1110 save_options ();
1111
1112 return FALSE(0);
1113}
1114
1115static gchar *
1116get_desktop_dir (void)
1117{
1118 gboolean desktop_is_home_dir = FALSE(0);
1119 gchar *desktop_dir;
1120
1121 /* Check if caja schema is installed before trying to read settings */
1122 GSettingsSchema *schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1123 CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences",
1124 FALSE(0));
1125
1126 if (schema != NULL((void*)0)) {
1127 GSettings *caja_prefs;
1128
1129 caja_prefs = g_settings_new (CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences");
1130 desktop_is_home_dir = g_settings_get_boolean (caja_prefs, "desktop-is-home-dir");
1131
1132 g_object_unref (caja_prefs);
1133 g_settings_schema_unref (schema);
1134 }
1135
1136 if (desktop_is_home_dir)
1137 desktop_dir = g_strconcat ("file://", g_get_home_dir (), NULL((void*)0));
1138 else
1139 desktop_dir = g_strconcat ("file://", g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), NULL((void*)0));
1140
1141 return desktop_dir;
1142}
1143
1144/* Taken from mate-vfs-utils.c */
1145static char *
1146expand_initial_tilde (const char *path)
1147{
1148 char *slash_after_user_name, *user_name;
1149 struct passwd *passwd_file_entry;
1150
1151 if (path[1] == '/' || path[1] == '\0') {
1152 return g_strconcat (g_get_home_dir (), &path[1], NULL((void*)0));
1153 }
1154
1155 slash_after_user_name = strchr (&path[1], '/');
1156 if (slash_after_user_name == NULL((void*)0)) {
1157 user_name = g_strdup (&path[1])g_strdup_inline (&path[1]);
1158 } else {
1159 user_name = g_strndup (&path[1],
1160 slash_after_user_name - &path[1]);
1161 }
1162 passwd_file_entry = getpwnam (user_name);
1163 g_free (user_name);
1164
1165 if (passwd_file_entry == NULL((void*)0) || passwd_file_entry->pw_dir == NULL((void*)0)) {
1166 return g_strdup (path)g_strdup_inline (path);
1167 }
1168
1169 return g_strconcat (passwd_file_entry->pw_dir,
1170 slash_after_user_name,
1171 NULL((void*)0));
1172}
1173
1174/* Load options */
1175static void
1176load_options (void)
1177{
1178 /* Find various dirs */
1179 last_save_dir = g_settings_get_string (settings,
1180 LAST_SAVE_DIRECTORY_KEY"last-save-directory");
1181
1182 if (*last_save_dir == '\0')
1183 {
1184 g_free (last_save_dir);
1185 last_save_dir = get_desktop_dir ();
1186 }
1187 else if (last_save_dir[0] == '~')
1188 {
1189 char *tmp = expand_initial_tilde (last_save_dir);
1190 g_free (last_save_dir);
1191 last_save_dir = tmp;
1192 }
1193
1194 include_border = g_settings_get_boolean (settings,
1195 INCLUDE_BORDER_KEY"include-border");
1196
1197 include_pointer = g_settings_get_boolean (settings,
1198 INCLUDE_POINTER_KEY"include-pointer");
1199
1200 border_effect = g_settings_get_string (settings,
1201 BORDER_EFFECT_KEY"border-effect");
1202 if (!border_effect)
1203 border_effect = g_strdup ("none")g_strdup_inline ("none");
1204
1205 delay = g_settings_get_int (settings, DELAY_KEY"delay");
1206}
1207
1208static void
1209save_options (void)
1210{
1211 g_settings_set_boolean (settings,
1212 INCLUDE_BORDER_KEY"include-border", include_border);
1213 g_settings_set_boolean (settings,
1214 INCLUDE_POINTER_KEY"include-pointer", include_pointer);
1215 g_settings_set_int (settings, DELAY_KEY"delay", delay);
1216 g_settings_set_string (settings,
1217 BORDER_EFFECT_KEY"border-effect", border_effect);
1218}
1219
1220void
1221loop_dialog_screenshot (void)
1222{
1223 /* interactive mode overrides everything */
1224 if (interactive_arg)
1225 {
1226 GtkWidget *dialog;
1227 gint response;
1228
1229 dialog = create_interactive_dialog ();
1230 response = gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
1231 gtk_widget_destroy (dialog);
1232
1233 switch (response)
1234 {
1235 case GTK_RESPONSE_DELETE_EVENT:
1236 case GTK_RESPONSE_CANCEL:
1237 return;
1238 case GTK_RESPONSE_OK:
1239 break;
1240 default:
1241 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "mate-screenshot.c"
, 1241, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1242 break;
1243 }
1244 }
1245
1246 if (((delay > 0 && interactive_arg) || delay_arg > 0) &&
1247 !take_area_shot)
1248 {
1249 g_timeout_add (delay * 1000,
1250 prepare_screenshot_timeout,
1251 NULL((void*)0));
1252 }
1253 else
1254 {
1255 if (interactive_arg)
1256 {
1257 /* HACK: give time to the dialog to actually disappear.
1258 * We don't have any way to tell when the compositor has finished
1259 * re-drawing.
1260 */
1261 g_timeout_add (200,
1262 prepare_screenshot_timeout, NULL((void*)0));
1263 }
1264 else
1265 g_idle_add (prepare_screenshot_timeout, NULL((void*)0));
1266 }
1267
1268 gtk_main ();
1269}
1270
1271/* main */
1272int
1273main (int argc, char *argv[])
1274{
1275 GOptionContext *context;
1276 gboolean window_arg = FALSE(0);
1277 gboolean area_arg = FALSE(0);
1278 gboolean include_border_arg = FALSE(0);
1279 gboolean disable_border_arg = FALSE(0);
1280 gchar *border_effect_arg = NULL((void*)0);
1281 gboolean version_arg = FALSE(0);
1282 GError *error = NULL((void*)0);
1283
1284 const GOptionEntry entries[] = {
1285 { "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen")("Grab a window instead of the entire screen"), NULL((void*)0) },
1286 { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen")("Grab an area of the screen instead of the entire screen"), NULL((void*)0) },
1287 { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &noninteractive_clipboard_arg, N_("Send grabbed area directly to the clipboard")("Send grabbed area directly to the clipboard"), NULL((void*)0) },
1288 { "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot")("Include the window border with the screenshot"), NULL((void*)0) },
1289 { "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot")("Remove the window border from the screenshot"), NULL((void*)0) },
1290 { "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]")("Take screenshot after specified delay [in seconds]"), N_("seconds")("seconds") },
1291 { "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)")("Effect to add to the border (shadow, border or none)"), N_("effect")("effect") },
1292 { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options")("Interactively set options"), NULL((void*)0) },
1293 { "version", 0, 0, G_OPTION_ARG_NONE, &version_arg, N_("Print version information and exit")("Print version information and exit"), NULL((void*)0) },
1294 { NULL((void*)0), 0, 0, G_OPTION_ARG_NONE, NULL((void*)0), NULL((void*)0), NULL((void*)0) },
1295 };
1296
1297#ifdef ENABLE_NLS1
1298 setlocale (LC_ALL6, "");
1299 bindtextdomain (GETTEXT_PACKAGE"mate-utils", MATELOCALEDIR"/usr/local/share/locale");
1300 bind_textdomain_codeset (GETTEXT_PACKAGE"mate-utils", "UTF-8");
1301 textdomain (GETTEXT_PACKAGE"mate-utils");
1302#endif /* ENABLE_NLS */
1303
1304 context = g_option_context_new (_("Take a picture of the screen")gettext ("Take a picture of the screen"));
1305 g_option_context_set_ignore_unknown_options (context, FALSE(0));
1306 g_option_context_set_help_enabled (context, TRUE(!(0)));
1307 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE"mate-utils");
1308 g_option_context_add_group (context, gtk_get_option_group (TRUE(!(0))));
1309
1310 g_option_context_parse (context, &argc, &argv, &error);
1311
1312 if (error) {
1313 g_critical ("Unable to parse arguments: %s", error->message);
1314 g_error_free (error);
1315 g_option_context_free (context);
1316 exit (1);
1317 }
1318
1319 g_option_context_free (context);
1320
1321 if (version_arg) {
1322 g_print ("%s %s\n", g_get_application_name (), VERSION"1.27.0");
1323 exit (EXIT_SUCCESS0);
1324 }
1325
1326 if (interactive_arg && noninteractive_clipboard_arg) {
This statement is never executed
1327 g_printerr (_("Conflicting options: --clipboard and --interactive should not be "gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
1328 "used at the same time.\n")gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
);
1329 exit (1);
1330 }
1331
1332 if (window_arg && area_arg) {
1333 g_printerr (_("Conflicting options: --window and --area should not be "gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
1334 "used at the same time.\n")gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
);
1335 exit (1);
1336 }
1337
1338 gtk_window_set_default_icon_name (SCREENSHOOTER_ICON"applets-screenshooter");
1339
1340 settings = g_settings_new (MATE_SCREENSHOT_SCHEMA"org.mate.screenshot");
1341 load_options ();
1342 /* allow the command line to override options */
1343 if (window_arg)
1344 take_window_shot = TRUE(!(0));
1345
1346 if (area_arg)
1347 take_area_shot = TRUE(!(0));
1348
1349 if (include_border_arg)
1350 include_border = TRUE(!(0));
1351
1352 if (disable_border_arg)
1353 include_border = FALSE(0);
1354
1355 if (border_effect_arg)
1356 {
1357 g_free (border_effect);
1358 border_effect = border_effect_arg;
1359 }
1360
1361 if (delay_arg > 0)
1362 delay = delay_arg;
1363
1364 loop_dialog_screenshot();
1365
1366 return EXIT_SUCCESS0;
1367}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-1f8d97.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-1f8d97.html new file mode 100644 index 00000000..4539caeb --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-1f8d97.html @@ -0,0 +1,2893 @@ + + + +gdict-client-context.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

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

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-client-context.c
Warning:line 1397, column 13
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-client-context.c
Warning:line 1504, column 8
Dereference of null pointer
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

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

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:mate-dictionary/src/gdict-applet.c
Warning:line 159, column 17
1st function call argument is an uninitialized value
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gdict-applet.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 static -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/mate-dictionary/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D PREFIX="/usr/local" -D SYSCONFDIR="/usr/local/etc" -D LIBDIR="/usr/local/lib" -D DATADIR="/usr/local/share" -D PKGDATADIR="/usr/local/share/mate-dictionary" -D MATELOCALEDIR="/usr/local/share/locale" -I ../../mate-dictionary -I ../../mate-dictionary -I /usr/include/mate-panel-4.0/libmate-panel-applet -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-dictionary/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c gdict-applet.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2005 Emmanuele Bassi <ebassi@gmail.com>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H1
21#include <config.h>
22#endif
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include <glib/gi18n.h>
29#include <gio/gio.h>
30#include <gtk/gtk.h>
31#include <gdk/gdkkeysyms.h>
32#include <gdk-pixbuf/gdk-pixbuf.h>
33
34#include "gdict-applet.h"
35#include "gdict-about.h"
36#include "gdict-pref-dialog.h"
37#include "gdict-print.h"
38#include "gdict-common.h"
39#include "gdict-aligned-window.h"
40
41#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
42#include <gdk/gdkwayland.h>
43#include <gtk-layer-shell/gtk-layer-shell.h>
44#endif
45
46#define GDICT_APPLET_CLASS(klass)((((GdictAppletClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((gdict_applet_get_type ()))))))
(G_TYPE_CHECK_CLASS_CAST ((klass), GDICT_TYPE_APPLET, GdictAppletClass)(((GdictAppletClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((gdict_applet_get_type ())))))
)
47#define GDICT_APPLET_GET_CLASS(obj)((((GdictAppletClass*) (((GTypeInstance*) ((obj)))->g_class
))))
(G_TYPE_INSTANCE_GET_CLASS ((obj), GDICT_TYPE_APPLET, GdictAppletClass)(((GdictAppletClass*) (((GTypeInstance*) ((obj)))->g_class
)))
)
48
49struct _GdictAppletClass
50{
51 MatePanelAppletClass parent_class;
52};
53
54struct _GdictAppletPrivate
55{
56 guint size;
57 GtkOrientation orient;
58
59 GSettings *settings;
60 GSettings *desktop_settings;
61
62 gchar *database;
63 gchar *strategy;
64 gchar *source_name;
65 gchar *print_font;
66 gchar *defbox_font;
67
68 gchar *word;
69 GdictContext *context;
70 guint lookup_start_id;
71 guint lookup_end_id;
72 guint error_id;
73
74 GdictSourceLoader *loader;
75
76 GtkWidget *box;
77 GtkWidget *toggle;
78 GtkWidget *image;
79 GtkWidget *entry;
80 GtkWidget *window;
81 GtkWidget *frame;
82 GtkWidget *defbox;
83
84 GtkActionGroup* context_menu_action_group;
85
86 guint idle_draw_id;
87
88 GdkPixbuf *icon;
89
90 gint window_width;
91 gint window_height;
92
93 guint is_window_showing : 1;
94};
95
96#define WINDOW_MIN_WIDTH300 300
97#define WINDOW_MIN_HEIGHT200 200
98#define WINDOW_NUM_COLUMNS47 47
99#define WINDOW_NUM_ROWS20 20
100
101G_DEFINE_TYPE_WITH_PRIVATE (GdictApplet, gdict_applet, PANEL_TYPE_APPLET)static void gdict_applet_init (GdictApplet *self); static void
gdict_applet_class_init (GdictAppletClass *klass); static GType
gdict_applet_get_type_once (void); static gpointer gdict_applet_parent_class
= ((void*)0); static gint GdictApplet_private_offset; static
void gdict_applet_class_intern_init (gpointer klass) { gdict_applet_parent_class
= g_type_class_peek_parent (klass); if (GdictApplet_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictApplet_private_offset
); gdict_applet_class_init ((GdictAppletClass*) klass); } __attribute__
((__unused__)) static inline gpointer gdict_applet_get_instance_private
(GdictApplet *self) { return (((gpointer) ((guint8*) (self) +
(glong) (GdictApplet_private_offset)))); } GType gdict_applet_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_applet_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_applet_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(mate_panel_applet_get_type (), g_intern_static_string ("GdictApplet"
), sizeof (GdictAppletClass), (GClassInitFunc)(void (*)(void)
) gdict_applet_class_intern_init, sizeof (GdictApplet), (GInstanceInitFunc
)(void (*)(void)) gdict_applet_init, (GTypeFlags) 0); { {{ GdictApplet_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (GdictAppletPrivate
)); };} } return g_define_type_id; }
;
102
103static void
104set_atk_name_description (GtkWidget *widget,
105 const char *name,
106 const char *description)
107{
108 AtkObject *aobj;
109
110 aobj = gtk_widget_get_accessible (widget);
111 if (!GTK_IS_ACCESSIBLE (aobj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(aobj)); GType __t = ((gtk_accessible_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
112 return;
113
114 atk_object_set_name (aobj, name);
115 atk_object_set_description (aobj, description);
116}
117
118static void
119set_window_default_size (GdictApplet *applet)
120{
121 GdictAppletPrivate *priv = applet->priv;
122 GtkWidget *widget, *defbox;
123 gint width, height;
124 gint font_size;
125 GdkDisplay *display;
2
'display' declared without an initial value
126 GdkMonitor *monitor_num;
127 GtkRequisition req;
128 GdkRectangle monitor;
129
130 if (!priv->window)
3
Assuming field 'window' is non-null
4
Taking false branch
131 return;
132
133 widget = priv->window;
134 defbox = priv->defbox;
135
136 /* Size based on the font size */
137 font_size = pango_font_description_get_size (gtk_widget_get_style (defbox)->font_desc);
138 font_size = PANGO_PIXELS (font_size)(((int)(font_size) + 512) >> 10);
139
140#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
141 display = gtk_widget_get_display (widget);
142 if (GDK_IS_WAYLAND_DISPLAY (display))
143 width = font_size * WINDOW_NUM_COLUMNS47 - 100;
144
145 else
146#endif
147 {
148 width = font_size * WINDOW_NUM_COLUMNS47;
149 }
150
151 height = font_size * WINDOW_NUM_ROWS20;
152
153 /* Use at least the requisition size of the window... */
154 gtk_widget_get_preferred_size (widget, NULL((void*)0), &req);
155 width = MAX (width, req.width)(((width) > (req.width)) ? (width) : (req.width));
5
Assuming 'width' is > field 'width'
6
'?' condition is true
156 height = MAX (height, req.height)(((height) > (req.height)) ? (height) : (req.height));
7
Assuming 'height' is > field 'height'
8
'?' condition is true
157
158 /* ... but make it no larger than half the monitor size */
159 monitor_num = gdk_display_get_monitor_at_window (display,
9
1st function call argument is an uninitialized value
160 gtk_widget_get_window (widget));
161 gdk_monitor_get_geometry (monitor_num, &monitor);
162
163 width = MIN (width, monitor.width / 2)(((width) < (monitor.width / 2)) ? (width) : (monitor.width
/ 2))
;
164 height = MIN (height, monitor.height / 2)(((height) < (monitor.height / 2)) ? (height) : (monitor.height
/ 2))
;
165
166 /* Set size */
167 gtk_widget_set_size_request (priv->frame, width, height);
168}
169
170static void
171clear_cb (GtkWidget *widget,
172 GdictApplet *applet)
173{
174 GdictAppletPrivate *priv = applet->priv;
175
176 gtk_entry_set_text (GTK_ENTRY (priv->entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_entry_get_type ()))))))
, "");
177
178 if (!priv->defbox)
179 return;
180
181 gdict_defbox_clear (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
);
182}
183
184static void
185print_cb (GtkWidget *widget,
186 GdictApplet *applet)
187{
188 GdictAppletPrivate *priv = applet->priv;
189
190 if (!priv->defbox)
191 return;
192
193 gdict_show_print_dialog (GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
,
194 GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
);
195}
196
197static void
198save_cb (GtkWidget *widget,
199 GdictApplet *applet)
200{
201 GdictAppletPrivate *priv = applet->priv;
202 GtkWidget *dialog;
203
204 if (!priv->defbox)
205 return;
206
207 dialog = gtk_file_chooser_dialog_new (_("Save a Copy")gettext ("Save a Copy"),
208 GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
,
209 GTK_FILE_CHOOSER_ACTION_SAVE,
210 "gtk-cancel", GTK_RESPONSE_CANCEL,
211 "gtk-save", GTK_RESPONSE_ACCEPT,
212 NULL((void*)0));
213 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
, TRUE(!(0)));
214
215 /* default to user's $HOME */
216 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
, g_get_home_dir ());
217 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
, _("Untitled document")gettext ("Untitled document"));
218
219 if (gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
) == GTK_RESPONSE_ACCEPT)
220 {
221 gchar *filename;
222 gchar *text;
223 gsize len;
224 GError *write_error = NULL((void*)0);
225
226 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
);
227
228 text = gdict_defbox_get_text (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, &len);
229
230 g_file_set_contents (filename,
231 text,
232 len,
233 &write_error);
234 if (write_error)
235 {
236 gchar *message;
237
238 message = g_strdup_printf (_("Error while writing to '%s'")gettext ("Error while writing to '%s'"), filename);
239
240 gdict_show_error_dialog (GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
,
241 message,
242 write_error->message);
243
244 g_error_free (write_error);
245 g_free (message);
246 }
247
248 g_free (text);
249 g_free (filename);
250 }
251
252 gtk_widget_destroy (dialog);
253}
254
255static void
256gdict_applet_set_menu_items_sensitive (GdictApplet *applet,
257 gboolean is_sensitive)
258{
259 GtkAction *action;
260
261 action = gtk_action_group_get_action (applet->priv->context_menu_action_group,
262 "DictionaryClear");
263 gtk_action_set_sensitive (action, is_sensitive);
264 action = gtk_action_group_get_action (applet->priv->context_menu_action_group,
265 "DictionaryPrint");
266 gtk_action_set_sensitive (action, is_sensitive);
267 action = gtk_action_group_get_action (applet->priv->context_menu_action_group,
268 "DictionarySave");
269 gtk_action_set_sensitive (action, is_sensitive);
270
271 return;
272}
273
274static gboolean
275window_key_press_event_cb (GtkWidget *widget,
276 GdkEventKey *event,
277 gpointer user_data)
278{
279 GdictApplet *applet = GDICT_APPLET (user_data)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((gdict_applet_get_type ()))))))
;
280
281 if (event->keyval == GDK_KEY_Escape0xff1b)
282 {
283 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (applet->priv->toggle)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet->priv->toggle)), ((gtk_toggle_button_get_type
()))))))
, FALSE(0));
284 gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (applet->priv->toggle)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet->priv->toggle)), ((gtk_toggle_button_get_type
()))))))
);
285
286 return TRUE(!(0));
287 }
288 else if ((event->keyval == GDK_KEY_l0x06c) &&
289 (event->state & GDK_CONTROL_MASK))
290 {
291 gtk_widget_grab_focus (applet->priv->entry);
292
293 return TRUE(!(0));
294 }
295
296 return FALSE(0);
297}
298
299static void
300window_show_cb (GtkWidget *window,
301 GdictApplet *applet)
302{
303 set_window_default_size (applet);
1
Calling 'set_window_default_size'
304}
305
306static void
307gdict_applet_build_window (GdictApplet *applet)
308{
309 GdictAppletPrivate *priv = applet->priv;
310 GtkWidget *window;
311 GtkWidget *frame;
312 GtkWidget *vbox;
313 GtkWidget *bbox;
314 GtkWidget *button;
315
316 if (!priv->entry)
317 {
318 g_warning ("No entry widget defined");
319
320 return;
321 }
322
323 window = gdict_aligned_window_new (priv->toggle);
324 g_signal_connect (window, "key-press-event",g_signal_connect_data ((window), ("key-press-event"), (((GCallback
) (window_key_press_event_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
325 G_CALLBACK (window_key_press_event_cb),g_signal_connect_data ((window), ("key-press-event"), (((GCallback
) (window_key_press_event_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
326 applet)g_signal_connect_data ((window), ("key-press-event"), (((GCallback
) (window_key_press_event_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
;
327 g_signal_connect (window, "show",g_signal_connect_data ((window), ("show"), (((GCallback) (window_show_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
328 G_CALLBACK (window_show_cb),g_signal_connect_data ((window), ("show"), (((GCallback) (window_show_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
329 applet)g_signal_connect_data ((window), ("show"), (((GCallback) (window_show_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
;
330
331#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
332 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
333 if ((GDK_IS_WAYLAND_DISPLAY (display)) && (!gtk_layer_is_layer_window (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
)))
334 {
335 gtk_layer_init_for_window (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
);
336 gtk_layer_set_layer (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, GTK_LAYER_SHELL_LAYER_TOP);
337 gtk_layer_set_keyboard_mode (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
338 }
339#endif
340 frame = gtk_frame_new (NULL((void*)0));
341 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
, GTK_SHADOW_IN);
342 gtk_container_add (GTK_CONTAINER (window)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_container_get_type ()))))))
, frame);
343 gtk_widget_show (frame);
344 priv->frame = frame;
345
346 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
347 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 6);
348 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, vbox);
349 gtk_widget_show (vbox);
350
351 priv->defbox = gdict_defbox_new ();
352 if (priv->context)
353 gdict_defbox_set_context (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, priv->context);
354
355 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, priv->defbox, TRUE(!(0)), TRUE(!(0)), 0);
356 gtk_widget_show (priv->defbox);
357 gtk_widget_set_can_focus (priv->defbox, TRUE(!(0)));
358 gtk_widget_set_can_default (priv->defbox, TRUE(!(0)));
359
360 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
361 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox)((((GtkButtonBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_button_box_get_type ()))))))
, GTK_BUTTONBOX_END);
362 gtk_box_set_spacing (GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, 6);
363
364#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
365 if (GDK_IS_WAYLAND_DISPLAY (display))
366 {
367 gtk_box_pack_start (GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, priv->entry, TRUE(!(0)), TRUE(!(0)), 0);
368 gtk_button_box_set_child_non_homogeneous(GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, priv->entry, TRUE(!(0)));
369 }
370#endif
371 gtk_box_pack_end (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, bbox, FALSE(0), FALSE(0), 0);
372 gtk_widget_show (bbox);
373
374 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-clear"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
375 "label", "gtk-clear",((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-clear"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
376 "use-stock", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-clear"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
377 "use-underline", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-clear"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
378 NULL))((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-clear"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
;
379
380 gtk_widget_set_tooltip_text (button, _("Clear the definitions found")gettext ("Clear the definitions found"));
381 set_atk_name_description (button,
382 _("Clear definition")gettext ("Clear definition"),
383 _("Clear the text of the definition")gettext ("Clear the text of the definition"));
384
385 g_signal_connect (button, "clicked", G_CALLBACK (clear_cb), applet)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
clear_cb))), (applet), ((void*)0), (GConnectFlags) 0)
;
386 gtk_box_pack_start (GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, button, FALSE(0), FALSE(0), 0);
387 gtk_widget_show (button);
388
389 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-print"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
390 "label", "gtk-print",((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-print"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
391 "use-stock", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-print"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
392 "use-underline", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-print"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
393 NULL))((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-print"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
;
394
395 gtk_widget_set_tooltip_text (button, _("Print the definitions found")gettext ("Print the definitions found"));
396 set_atk_name_description (button,
397 _("Print definition")gettext ("Print definition"),
398 _("Print the text of the definition")gettext ("Print the text of the definition"));
399
400 g_signal_connect (button, "clicked", G_CALLBACK (print_cb), applet)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
print_cb))), (applet), ((void*)0), (GConnectFlags) 0)
;
401 gtk_box_pack_start (GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, button, FALSE(0), FALSE(0), 0);
402 gtk_widget_show (button);
403
404 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-save"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
405 "label", "gtk-save",((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-save"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
406 "use-stock", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-save"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
407 "use-underline", TRUE,((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-save"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
408 NULL))((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new ((gtk_button_get_type ()), "label", "gtk-save"
, "use-stock", (!(0)), "use-underline", (!(0)), ((void*)0))))
, ((gtk_widget_get_type ()))))))
;
409
410 gtk_widget_set_tooltip_text (button, _("Save the definitions found")gettext ("Save the definitions found"));
411 set_atk_name_description (button,
412 _("Save definition")gettext ("Save definition"),
413 _("Save the text of the definition to a file")gettext ("Save the text of the definition to a file"));
414
415 g_signal_connect (button, "clicked", G_CALLBACK (save_cb), applet)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
save_cb))), (applet), ((void*)0), (GConnectFlags) 0)
;
416 gtk_box_pack_start (GTK_BOX (bbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bbox)), ((gtk_box_get_type ()))))))
, button, FALSE(0), FALSE(0), 0);
417 gtk_widget_show (button);
418
419#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
420 if (GDK_IS_WAYLAND_DISPLAY (display))
421 gtk_widget_show (priv->entry);
422#endif
423
424 gtk_window_set_default (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, priv->defbox);
425
426 priv->window = window;
427 priv->is_window_showing = FALSE(0);
428}
429
430static gboolean
431gdict_applet_icon_toggled_cb (GtkWidget *widget,
432 GdictApplet *applet)
433{
434 GdictAppletPrivate *priv = applet->priv;
435
436 if (!priv->window)
437 gdict_applet_build_window (applet);
438
439 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gtk_toggle_button_get_type ()))))))
))
440 {
441 gtk_window_set_screen (GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
,
442 gtk_widget_get_screen (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
));
443 gtk_window_present (GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
);
444 gtk_widget_grab_focus (priv->defbox);
445
446 priv->is_window_showing = TRUE(!(0));
447 }
448 else
449 {
450 /* force hiding the find pane */
451 gdict_defbox_set_show_find (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, FALSE(0));
452
453 gtk_widget_grab_focus (priv->entry);
454 gtk_widget_hide (priv->window);
455
456 priv->is_window_showing = FALSE(0);
457 }
458
459 return FALSE(0);
460}
461
462static void
463gdict_applet_entry_activate_cb (GtkWidget *widget,
464 GdictApplet *applet)
465{
466 GdictAppletPrivate *priv = applet->priv;
467 gchar *text;
468
469 text = gtk_editable_get_chars (GTK_EDITABLE (widget)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gtk_editable_get_type ()))))))
, 0, -1);
470 if (!text)
471 return;
472
473 g_free (priv->word);
474 priv->word = text;
475
476 if (!priv->window)
477 gdict_applet_build_window (applet);
478
479 gdict_defbox_lookup (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, priv->word);
480}
481
482static gboolean
483gdict_applet_entry_key_press_cb (GtkWidget *widget,
484 GdkEventKey *event,
485 gpointer user_data)
486{
487 GdictAppletPrivate *priv = GDICT_APPLET (user_data)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((gdict_applet_get_type ()))))))
->priv;
488
489 if (event->keyval == GDK_KEY_Escape0xff1b)
490 {
491 if (priv->is_window_showing)
492 {
493 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->toggle)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->toggle)), ((gtk_toggle_button_get_type ()))))))
, FALSE(0));
494 gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (priv->toggle)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->toggle)), ((gtk_toggle_button_get_type ()))))))
);
495
496 return TRUE(!(0));
497 }
498 }
499 else if (event->keyval == GDK_KEY_Tab0xff09)
500 {
501 if (priv->is_window_showing)
502 gtk_widget_grab_focus (priv->defbox);
503 }
504
505 return FALSE(0);
506}
507
508static gboolean
509gdict_applet_icon_button_press_event_cb (GtkWidget *widget,
510 GdkEventButton *event,
511 GdictApplet *applet)
512{
513 GdictAppletPrivate *priv = applet->priv;
514
515 /* we don't want to block the applet's popup menu unless the
516 * user is toggling the button
517 */
518 if (event->button != 1)
519 g_signal_stop_emission_by_name (priv->toggle, "button-press-event");
520
521#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
522 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
523 if ((GDK_IS_WAYLAND_DISPLAY (display)) && (GTK_IS_WIDGET (priv->window)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(priv->window)); GType __t = ((gtk_widget_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) && (event->button == 1))
524 gtk_widget_show_all (GTK_WIDGET (priv->window)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_widget_get_type ()))))))
);
525#endif
526 return FALSE(0);
527}
528
529static gboolean
530gdict_applet_entry_button_press_event_cb (GtkWidget *widget,
531 GdkEventButton *event,
532 GdictApplet *applet)
533{
534 mate_panel_applet_request_focus (MATE_PANEL_APPLET (applet), event->time);
535
536 return FALSE(0);
537}
538
539static gboolean
540gdict_applet_draw (GdictApplet *applet)
541{
542 GdictAppletPrivate *priv = applet->priv;
543 GtkWidget *box;
544 GtkWidget *hbox;
545 gchar *text = NULL((void*)0);
546
547 if (priv->entry)
548 text = gtk_editable_get_chars (GTK_EDITABLE (priv->entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_editable_get_type ()))))))
, 0, -1);
549
550 if (priv->box)
551 gtk_widget_destroy (priv->box);
552
553 box = gtk_box_new (priv->orient, 0);
554
555 gtk_container_add (GTK_CONTAINER (applet)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_container_get_type ()))))))
, box);
556 gtk_widget_show (box);
557
558 /* toggle button */
559 priv->toggle = gtk_toggle_button_new ();
560 gtk_widget_set_tooltip_text (priv->toggle, _("Click to view the dictionary window")gettext ("Click to view the dictionary window"));
561 set_atk_name_description (priv->toggle,
562 _("Toggle dictionary window")gettext ("Toggle dictionary window"),
563 _("Show or hide the definition window")gettext ("Show or hide the definition window"));
564
565 gtk_button_set_relief (GTK_BUTTON (priv->toggle)((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->toggle)), ((gtk_button_get_type ()))))))
,
566 GTK_RELIEF_NONE);
567 g_signal_connect (priv->toggle, "toggled",g_signal_connect_data ((priv->toggle), ("toggled"), (((GCallback
) (gdict_applet_icon_toggled_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
568 G_CALLBACK (gdict_applet_icon_toggled_cb),g_signal_connect_data ((priv->toggle), ("toggled"), (((GCallback
) (gdict_applet_icon_toggled_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
569 applet)g_signal_connect_data ((priv->toggle), ("toggled"), (((GCallback
) (gdict_applet_icon_toggled_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
;
570 g_signal_connect (priv->toggle, "button-press-event",g_signal_connect_data ((priv->toggle), ("button-press-event"
), (((GCallback) (gdict_applet_icon_button_press_event_cb))),
(applet), ((void*)0), (GConnectFlags) 0)
571 G_CALLBACK (gdict_applet_icon_button_press_event_cb),g_signal_connect_data ((priv->toggle), ("button-press-event"
), (((GCallback) (gdict_applet_icon_button_press_event_cb))),
(applet), ((void*)0), (GConnectFlags) 0)
572 applet)g_signal_connect_data ((priv->toggle), ("button-press-event"
), (((GCallback) (gdict_applet_icon_button_press_event_cb))),
(applet), ((void*)0), (GConnectFlags) 0)
;
573 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, priv->toggle, FALSE(0), FALSE(0), 0);
574 gtk_widget_show (priv->toggle);
575
576 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
577 gtk_container_set_border_width (GTK_CONTAINER (hbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_container_get_type ()))))))
, 0);
578 gtk_container_add (GTK_CONTAINER (priv->toggle)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->toggle)), ((gtk_container_get_type ()))))))
, hbox);
579 gtk_widget_show (hbox);
580
581 if (priv->icon)
582 {
583 GdkPixbuf *scaled;
584
585 priv->image = gtk_image_new ();
586 gtk_image_set_pixel_size (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
, priv->size - 10);
587
588 scaled = gdk_pixbuf_scale_simple (priv->icon,
589 priv->size - 5,
590 priv->size - 5,
591 GDK_INTERP_BILINEAR);
592
593 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
, scaled);
594 g_object_unref (scaled);
595
596 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, priv->image, FALSE(0), FALSE(0), 0);
597
598 gtk_widget_show (priv->image);
599 }
600 else
601 {
602 priv->image = gtk_image_new ();
603
604 gtk_image_set_pixel_size (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
, priv->size - 10);
605 gtk_image_set_from_icon_name (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
,
606 "image-missing", -1);
607
608 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, priv->image, FALSE(0), FALSE(0), 0);
609 gtk_widget_show (priv->image);
610 }
611
612 /* entry */
613 priv->entry = gtk_entry_new ();
614#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
615 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
616 if (GDK_IS_WAYLAND_DISPLAY (display))
617 {
618 gtk_entry_set_icon_from_icon_name (GTK_ENTRY(priv->entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_entry_get_type ()))))))
, GTK_ENTRY_ICON_PRIMARY, "gtk-edit");
619 gtk_entry_set_icon_activatable (GTK_ENTRY(priv->entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_entry_get_type ()))))))
, GTK_ENTRY_ICON_PRIMARY, FALSE(0));
620 /*Fill the available space since we must move the entry to the popup window for wayland*/
621 }
622#endif
623 gtk_entry_set_width_chars (GTK_ENTRY (priv->entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_entry_get_type ()))))))
, 12);
624
625 gtk_widget_set_tooltip_text (priv->entry, _("Type the word you want to look up")gettext ("Type the word you want to look up"));
626 set_atk_name_description (priv->entry,
627 _("Dictionary entry")gettext ("Dictionary entry"),
628 _("Look up words in dictionaries")gettext ("Look up words in dictionaries"));
629
630 gtk_editable_set_editable (GTK_EDITABLE (priv->entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_editable_get_type ()))))))
, TRUE(!(0)));
631 g_signal_connect (priv->entry, "activate",g_signal_connect_data ((priv->entry), ("activate"), (((GCallback
) (gdict_applet_entry_activate_cb))), (applet), ((void*)0), (
GConnectFlags) 0)
632 G_CALLBACK (gdict_applet_entry_activate_cb),g_signal_connect_data ((priv->entry), ("activate"), (((GCallback
) (gdict_applet_entry_activate_cb))), (applet), ((void*)0), (
GConnectFlags) 0)
633 applet)g_signal_connect_data ((priv->entry), ("activate"), (((GCallback
) (gdict_applet_entry_activate_cb))), (applet), ((void*)0), (
GConnectFlags) 0)
;
634 g_signal_connect (priv->entry, "button-press-event",g_signal_connect_data ((priv->entry), ("button-press-event"
), (((GCallback) (gdict_applet_entry_button_press_event_cb)))
, (applet), ((void*)0), (GConnectFlags) 0)
635 G_CALLBACK (gdict_applet_entry_button_press_event_cb),g_signal_connect_data ((priv->entry), ("button-press-event"
), (((GCallback) (gdict_applet_entry_button_press_event_cb)))
, (applet), ((void*)0), (GConnectFlags) 0)
636 applet)g_signal_connect_data ((priv->entry), ("button-press-event"
), (((GCallback) (gdict_applet_entry_button_press_event_cb)))
, (applet), ((void*)0), (GConnectFlags) 0)
;
637 g_signal_connect (priv->entry, "key-press-event",g_signal_connect_data ((priv->entry), ("key-press-event"),
(((GCallback) (gdict_applet_entry_key_press_cb))), (applet),
((void*)0), (GConnectFlags) 0)
638 G_CALLBACK (gdict_applet_entry_key_press_cb),g_signal_connect_data ((priv->entry), ("key-press-event"),
(((GCallback) (gdict_applet_entry_key_press_cb))), (applet),
((void*)0), (GConnectFlags) 0)
639 applet)g_signal_connect_data ((priv->entry), ("key-press-event"),
(((GCallback) (gdict_applet_entry_key_press_cb))), (applet),
((void*)0), (GConnectFlags) 0)
;
640
641#if defined (ENABLE_WAYLAND) && defined (GDK_WINDOWING_WAYLAND)
642 if (GDK_IS_WAYLAND_DISPLAY (display))
643 {
644 GtkStyleContext *context = gtk_widget_get_style_context (priv->entry);
645 gtk_style_context_add_class (context, "view");
646 }
647 else
648#endif
649 {
650 gtk_box_pack_end (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, priv->entry, FALSE(0), FALSE(0), 0);
651 gtk_widget_show (priv->entry);
652 }
653
654 if (text)
655 {
656 gtk_entry_set_text (GTK_ENTRY (priv->entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_entry_get_type ()))))))
, text);
657
658 g_free (text);
659 }
660
661 priv->box = box;
662
663#if 0
664 gtk_widget_grab_focus (priv->entry);
665#endif
666
667 gtk_widget_show_all (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
);
668
669 return FALSE(0);
670}
671
672static void
673gdict_applet_queue_draw (GdictApplet *applet)
674{
675 if (!applet->priv->idle_draw_id)
676 applet->priv->idle_draw_id = g_idle_add ((GSourceFunc) gdict_applet_draw,
677 applet);
678}
679
680static void
681gdict_applet_lookup_start_cb (GdictContext *context,
682 GdictApplet *applet)
683{
684 GdictAppletPrivate *priv = applet->priv;
685
686 if (!priv->window)
687 gdict_applet_build_window (applet);
688
689 if (!priv->is_window_showing)
690 {
691 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->toggle)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->toggle)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
692
693 gtk_window_present (GTK_WINDOW (priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->window)), ((gtk_window_get_type ()))))))
);
694 gtk_widget_grab_focus (priv->defbox);
695
696 priv->is_window_showing = TRUE(!(0));
697 }
698
699 gdict_applet_set_menu_items_sensitive (applet, FALSE(0));
700}
701
702static void
703gdict_applet_lookup_end_cb (GdictContext *context,
704 GdictApplet *applet)
705{
706 gdict_applet_set_menu_items_sensitive (applet, TRUE(!(0)));
707
708 gtk_window_present (GTK_WINDOW (applet->priv->window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet->priv->window)), ((gtk_window_get_type ()))
))))
);
709}
710
711static void
712gdict_applet_error_cb (GdictContext *context,
713 const GError *error,
714 GdictApplet *applet)
715{
716 /* disable menu items */
717 gdict_applet_set_menu_items_sensitive (applet, FALSE(0));
718}
719
720static void
721gdict_applet_cmd_lookup (GtkAction *action,
722 GdictApplet *applet)
723{
724 GdictAppletPrivate *priv = applet->priv;
725 gchar *text = NULL((void*)0);;
726
727 text = gtk_editable_get_chars (GTK_EDITABLE (priv->entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->entry)), ((gtk_editable_get_type ()))))))
, 0, -1);
728 if (!text)
729 return;
730
731 g_free (priv->word);
732 priv->word = text;
733
734 if (!priv->window)
735 gdict_applet_build_window (applet);
736
737 gdict_defbox_lookup (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, priv->word);
738}
739
740static void
741gdict_applet_cmd_clear (GtkAction *action,
742 GdictApplet *applet)
743{
744 clear_cb (NULL((void*)0), applet);
745}
746
747static void
748gdict_applet_cmd_print (GtkAction *action,
749 GdictApplet *applet)
750{
751 print_cb (NULL((void*)0), applet);
752}
753
754static void
755gdict_applet_cmd_save (GtkAction *action,
756 GdictApplet *applet)
757{
758 save_cb (NULL((void*)0), applet);
759}
760
761static void
762gdict_applet_cmd_preferences (GtkAction *action,
763 GdictApplet *applet)
764{
765 gdict_show_pref_dialog (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
,
766 _("Dictionary Preferences")gettext ("Dictionary Preferences"),
767 applet->priv->loader);
768}
769
770static void
771gdict_applet_cmd_about (GtkAction *action,
772 GdictApplet *applet)
773{
774 gdict_show_about_dialog (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
);
775}
776
777static void
778gdict_applet_cmd_help (GtkAction *action,
779 GdictApplet *applet)
780{
781 GError *err = NULL((void*)0);
782
783 gtk_show_uri_on_window (NULL((void*)0),
784 "help:mate-dictionary/mate-dictionary-applet",
785 gtk_get_current_event_time (), &err);
786
787 if (err)
788 {
789 gdict_show_error_dialog (NULL((void*)0),
790 _("There was an error while displaying help")gettext ("There was an error while displaying help"),
791 err->message);
792 g_error_free (err);
793 }
794}
795
796static void
797gdict_applet_change_orient (MatePanelApplet *applet,
798 MatePanelAppletOrient orient)
799{
800 GdictAppletPrivate *priv = GDICT_APPLET (applet)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gdict_applet_get_type ()))))))
->priv;
801 guint new_size;
802 GtkAllocation allocation;
803
804 gtk_widget_get_allocation (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
, &allocation);
805 switch (orient)
806 {
807 case MATE_PANEL_APPLET_ORIENT_LEFT:
808 case MATE_PANEL_APPLET_ORIENT_RIGHT:
809 priv->orient = GTK_ORIENTATION_VERTICAL;
810 new_size = allocation.width;
811 break;
812 case MATE_PANEL_APPLET_ORIENT_UP:
813 case MATE_PANEL_APPLET_ORIENT_DOWN:
814 priv->orient = GTK_ORIENTATION_HORIZONTAL;
815 new_size = allocation.height;
816 break;
817 }
818
819 if (new_size != priv->size)
820 priv->size = new_size;
821
822 gdict_applet_queue_draw (GDICT_APPLET (applet)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gdict_applet_get_type ()))))))
);
823
824 if (MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_orient)
825 MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_orient (applet,
826 orient);
827}
828
829static void
830gdict_applet_size_allocate (GtkWidget *widget,
831 GdkRectangle *allocation)
832{
833 GdictApplet *applet = GDICT_APPLET (widget)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gdict_applet_get_type ()))))))
;
834 GdictAppletPrivate *priv = applet->priv;
835 guint new_size;
836
837 if (priv->orient == GTK_ORIENTATION_HORIZONTAL)
838 new_size = allocation->height;
839 else
840 new_size = allocation->width;
841
842 if (priv->size != new_size)
843 {
844 priv->size = new_size;
845
846 gtk_image_set_pixel_size (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
, priv->size - 10);
847
848 /* re-scale the icon, if it was found */
849 if (priv->icon)
850 {
851 GdkPixbuf *scaled;
852
853 scaled = gdk_pixbuf_scale_simple (priv->icon,
854 priv->size - 5,
855 priv->size - 5,
856 GDK_INTERP_BILINEAR);
857
858 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image)((((GtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->image)), ((gtk_image_get_type ()))))))
, scaled);
859 g_object_unref (scaled);
860 }
861 }
862
863 if (GTK_WIDGET_CLASS (gdict_applet_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((gdict_applet_parent_class)), ((gtk_widget_get_type ())))
)))
->size_allocate)
864 GTK_WIDGET_CLASS (gdict_applet_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((gdict_applet_parent_class)), ((gtk_widget_get_type ())))
)))
->size_allocate (widget,
865 allocation);
866}
867
868static void
869gdict_applet_style_set (GtkWidget *widget,
870 GtkStyle *old_style)
871{
872 if (GTK_WIDGET_CLASS (gdict_applet_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((gdict_applet_parent_class)), ((gtk_widget_get_type ())))
)))
->style_set)
873 GTK_WIDGET_CLASS (gdict_applet_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((gdict_applet_parent_class)), ((gtk_widget_get_type ())))
)))
->style_set (widget,
874 old_style);
875#if 0
876 set_window_default_size (GDICT_APPLET (widget)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gdict_applet_get_type ()))))))
);
877#endif
878}
879
880static void
881gdict_applet_set_database (GdictApplet *applet,
882 const gchar *database)
883{
884 GdictAppletPrivate *priv = applet->priv;
885
886 g_free (priv->database);
887
888 if (database != NULL((void*)0) && *database != '\0')
889 priv->database = g_strdup (database)g_strdup_inline (database);
890 else
891 priv->database = g_settings_get_string (priv->settings,
892 GDICT_SETTINGS_DATABASE_KEY"database");
893 if (priv->defbox)
894 gdict_defbox_set_database (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
,
895 priv->database);
896}
897
898static void
899gdict_applet_set_strategy (GdictApplet *applet,
900 const gchar *strategy)
901{
902 GdictAppletPrivate *priv = applet->priv;
903
904 g_free (priv->strategy);
905
906 if (strategy != NULL((void*)0) && *strategy != '\0')
907 priv->strategy = g_strdup (strategy)g_strdup_inline (strategy);
908 else
909 priv->strategy = g_settings_get_string (priv->settings,
910 GDICT_SETTINGS_STRATEGY_KEY"strategy");
911}
912
913static GdictContext *
914get_context_from_loader (GdictApplet *applet)
915{
916 GdictAppletPrivate *priv = applet->priv;
917 GdictSource *source;
918 GdictContext *retval;
919
920 if (!priv->source_name)
921 priv->source_name = g_strdup (GDICT_DEFAULT_SOURCE_NAME)g_strdup_inline ("Default");
922
923 source = gdict_source_loader_get_source (priv->loader,
924 priv->source_name);
925 if (!source)
926 {
927 gchar *detail;
928
929 detail = g_strdup_printf (_("No dictionary source available with name '%s'")gettext ("No dictionary source available with name '%s'"),
930 priv->source_name);
931
932 gdict_show_error_dialog (NULL((void*)0),
933 _("Unable to find dictionary source")gettext ("Unable to find dictionary source"),
934 detail);
935
936 g_free (detail);
937
938 return NULL((void*)0);
939 }
940
941 gdict_applet_set_database (applet, gdict_source_get_database (source));
942 gdict_applet_set_strategy (applet, gdict_source_get_strategy (source));
943
944 retval = gdict_source_get_context (source);
945 if (!retval)
946 {
947 gchar *detail;
948
949 detail = g_strdup_printf (_("No context available for source '%s'")gettext ("No context available for source '%s'"),
950 gdict_source_get_description (source));
951
952 gdict_show_error_dialog (NULL((void*)0),
953 _("Unable to create a context")gettext ("Unable to create a context"),
954 detail);
955
956 g_free (detail);
957 g_object_unref (source);
958
959 return NULL((void*)0);
960 }
961
962 g_object_unref (source);
963
964 return retval;
965}
966
967static void
968gdict_applet_set_print_font (GdictApplet *applet,
969 const gchar *print_font)
970{
971 GdictAppletPrivate *priv = applet->priv;
972
973 g_free (priv->print_font);
974
975 if (print_font != NULL((void*)0) && *print_font != '\0')
976 priv->print_font = g_strdup (print_font)g_strdup_inline (print_font);
977 else
978 priv->print_font = g_settings_get_string (priv->settings,
979 GDICT_SETTINGS_PRINT_FONT_KEY"print-font");
980}
981
982static void
983gdict_applet_set_defbox_font (GdictApplet *applet,
984 const gchar *defbox_font)
985{
986 GdictAppletPrivate *priv = applet->priv;
987
988 g_free (priv->defbox_font);
989
990 if (defbox_font != NULL((void*)0) && *defbox_font != '\0')
991 priv->defbox_font = g_strdup (defbox_font)g_strdup_inline (defbox_font);
992 else
993 priv->defbox_font = g_settings_get_string (priv->desktop_settings,
994 DOCUMENT_FONT_KEY"document-font-name");
995
996 if (priv->defbox)
997 gdict_defbox_set_font_name (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
,
998 priv->defbox_font);
999}
1000
1001static void
1002gdict_applet_set_context (GdictApplet *applet,
1003 GdictContext *context)
1004{
1005 GdictAppletPrivate *priv = applet->priv;
1006
1007 if (priv->context)
1008 {
1009 g_signal_handler_disconnect (priv->context, priv->lookup_start_id);
1010 g_signal_handler_disconnect (priv->context, priv->lookup_end_id);
1011 g_signal_handler_disconnect (priv->context, priv->error_id);
1012
1013 priv->lookup_start_id = 0;
1014 priv->lookup_end_id = 0;
1015 priv->error_id = 0;
1016
1017 g_object_unref (priv->context);
1018 priv->context = NULL((void*)0);
1019 }
1020
1021 if (priv->defbox)
1022 gdict_defbox_set_context (GDICT_DEFBOX (priv->defbox)((((GdictDefbox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->defbox)), ((gdict_defbox_get_type ()))))))
, context);
1023
1024 if (!context)
1025 return;
1026
1027 /* attach our callbacks */
1028 priv->lookup_start_id = g_signal_connect (context, "lookup-start",g_signal_connect_data ((context), ("lookup-start"), (((GCallback
) (gdict_applet_lookup_start_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
1029 G_CALLBACK (gdict_applet_lookup_start_cb),g_signal_connect_data ((context), ("lookup-start"), (((GCallback
) (gdict_applet_lookup_start_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
1030 applet)g_signal_connect_data ((context), ("lookup-start"), (((GCallback
) (gdict_applet_lookup_start_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
;
1031 priv->lookup_end_id = g_signal_connect (context, "lookup-end",g_signal_connect_data ((context), ("lookup-end"), (((GCallback
) (gdict_applet_lookup_end_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
1032 G_CALLBACK (gdict_applet_lookup_end_cb),g_signal_connect_data ((context), ("lookup-end"), (((GCallback
) (gdict_applet_lookup_end_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
1033 applet)g_signal_connect_data ((context), ("lookup-end"), (((GCallback
) (gdict_applet_lookup_end_cb))), (applet), ((void*)0), (GConnectFlags
) 0)
;
1034 priv->error_id = g_signal_connect (context, "error",g_signal_connect_data ((context), ("error"), (((GCallback) (gdict_applet_error_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
1035 G_CALLBACK (gdict_applet_error_cb),g_signal_connect_data ((context), ("error"), (((GCallback) (gdict_applet_error_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
1036 applet)g_signal_connect_data ((context), ("error"), (((GCallback) (gdict_applet_error_cb
))), (applet), ((void*)0), (GConnectFlags) 0)
;
1037
1038 priv->context = context;
1039}
1040
1041static void
1042gdict_applet_set_source_name (GdictApplet *applet,
1043 const gchar *source_name)
1044{
1045 GdictAppletPrivate *priv = applet->priv;
1046 GdictContext *context;
1047
1048 g_free (priv->source_name);
1049
1050 if (source_name != NULL((void*)0) && *source_name != '\0')
1051 priv->source_name = g_strdup (source_name)g_strdup_inline (source_name);
1052 else
1053 priv->source_name = g_settings_get_string (priv->settings,
1054 GDICT_SETTINGS_SOURCE_KEY"source-name");
1055
1056 context = get_context_from_loader (applet);
1057 gdict_applet_set_context (applet, context);
1058}
1059
1060static void
1061gdict_applet_settings_changed_cb (GSettings *settings,
1062 const gchar *key, GdictApplet *applet)
1063{
1064
1065 if (g_strcmp0 (key, GDICT_SETTINGS_PRINT_FONT_KEY"print-font") == 0)
1066 {
1067 gdict_applet_set_print_font (applet, NULL((void*)0));
1068 }
1069 else if (g_strcmp0 (key, GDICT_SETTINGS_SOURCE_KEY"source-name") == 0)
1070 {
1071 gdict_applet_set_source_name (applet, NULL((void*)0));
1072 }
1073 else if (g_strcmp0 (key, GDICT_SETTINGS_DATABASE_KEY"database") == 0)
1074 {
1075 gdict_applet_set_database (applet, NULL((void*)0));
1076 }
1077 else if (g_strcmp0 (key, GDICT_SETTINGS_STRATEGY_KEY"strategy") == 0)
1078 {
1079 gdict_applet_set_strategy (applet, NULL((void*)0));
1080 }
1081 else if (g_strcmp0 (key, DOCUMENT_FONT_KEY"document-font-name") == 0)
1082 {
1083 gdict_applet_set_defbox_font (applet, NULL((void*)0));
1084 }
1085}
1086
1087static void
1088gdict_applet_finalize (GObject *object)
1089{
1090 GdictApplet *applet = GDICT_APPLET (object)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((gdict_applet_get_type ()))))))
;
1091 GdictAppletPrivate *priv = applet->priv;
1092
1093 if (priv->idle_draw_id)
1094 g_source_remove (priv->idle_draw_id);
1095
1096 if (priv->context_menu_action_group)
1097 {
1098 g_object_unref (priv->context_menu_action_group);
1099 priv->context_menu_action_group = NULL((void*)0);
1100 }
1101
1102 if (priv->settings != NULL((void*)0))
1103 {
1104 g_object_unref (priv->settings);
1105 priv->settings = NULL((void*)0);
1106 }
1107
1108 if (priv->desktop_settings != NULL((void*)0))
1109 {
1110 g_object_unref (priv->desktop_settings);
1111 priv->desktop_settings = NULL((void*)0);
1112 }
1113
1114 if (priv->context)
1115 {
1116 if (priv->lookup_start_id)
1117 {
1118 g_signal_handler_disconnect (priv->context, priv->lookup_start_id);
1119 g_signal_handler_disconnect (priv->context, priv->lookup_end_id);
1120 g_signal_handler_disconnect (priv->context, priv->error_id);
1121 }
1122
1123 g_object_unref (priv->context);
1124 }
1125
1126 if (priv->loader)
1127 g_object_unref (priv->loader);
1128
1129 if (priv->icon)
1130 g_object_unref (priv->icon);
1131
1132 g_free (priv->source_name);
1133 g_free (priv->print_font);
1134 g_free (priv->defbox_font);
1135 g_free (priv->word);
1136
1137 G_OBJECT_CLASS (gdict_applet_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((gdict_applet_parent_class)), (((GType) ((20) << (2
))))))))
->finalize (object);
1138}
1139
1140static void
1141gdict_applet_class_init (GdictAppletClass *klass)
1142{
1143 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
1144 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((gtk_widget_get_type ()))))))
;
1145 MatePanelAppletClass *applet_class = MATE_PANEL_APPLET_CLASS (klass);
1146
1147 gobject_class->finalize = gdict_applet_finalize;
1148
1149 widget_class->size_allocate = gdict_applet_size_allocate;
1150 widget_class->style_set = gdict_applet_style_set;
1151
1152 applet_class->change_orient = gdict_applet_change_orient;
1153}
1154
1155static void
1156gdict_applet_init (GdictApplet *applet)
1157{
1158 GdictAppletPrivate *priv;
1159 gchar *data_dir;
1160
1161 priv = gdict_applet_get_instance_private (applet);
1162 applet->priv = priv;
1163
1164 if (!priv->loader)
1165 priv->loader = gdict_source_loader_new ();
1166
1167 /* add our data dir inside $HOME to the loader's search paths */
1168 data_dir = gdict_get_data_dir ();
1169 gdict_source_loader_add_search_path (priv->loader, data_dir);
1170 g_free (data_dir);
1171
1172 gtk_window_set_default_icon_name ("accessories-dictionary");
1173
1174 mate_panel_applet_set_flags (MATE_PANEL_APPLET (applet),
1175 MATE_PANEL_APPLET_EXPAND_MINOR);
1176
1177 priv->settings = g_settings_new (GDICT_SETTINGS_SCHEMA"org.mate.dictionary");
1178 priv->desktop_settings = g_settings_new (DESKTOP_SETTINGS_SCHEMA"org.mate.interface");
1179
1180 g_signal_connect (priv->settings, "changed",g_signal_connect_data ((priv->settings), ("changed"), (((GCallback
) (gdict_applet_settings_changed_cb))), (applet), ((void*)0),
(GConnectFlags) 0)
1181 G_CALLBACK (gdict_applet_settings_changed_cb), applet)g_signal_connect_data ((priv->settings), ("changed"), (((GCallback
) (gdict_applet_settings_changed_cb))), (applet), ((void*)0),
(GConnectFlags) 0)
;
1182
1183 g_signal_connect (priv->desktop_settings, "changed",g_signal_connect_data ((priv->desktop_settings), ("changed"
), (((GCallback) (gdict_applet_settings_changed_cb))), (applet
), ((void*)0), (GConnectFlags) 0)
1184 G_CALLBACK (gdict_applet_settings_changed_cb), applet)g_signal_connect_data ((priv->desktop_settings), ("changed"
), (((GCallback) (gdict_applet_settings_changed_cb))), (applet
), ((void*)0), (GConnectFlags) 0)
;
1185
1186 mate_panel_applet_set_background_widget (MATE_PANEL_APPLET (applet),
1187 GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
);
1188
1189 priv->size = mate_panel_applet_get_size (MATE_PANEL_APPLET (applet));
1190
1191 switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet)))
1192 {
1193 case MATE_PANEL_APPLET_ORIENT_LEFT:
1194 case MATE_PANEL_APPLET_ORIENT_RIGHT:
1195 priv->orient = GTK_ORIENTATION_VERTICAL;
1196 break;
1197 case MATE_PANEL_APPLET_ORIENT_UP:
1198 case MATE_PANEL_APPLET_ORIENT_DOWN:
1199 priv->orient = GTK_ORIENTATION_HORIZONTAL;
1200 break;
1201 }
1202
1203 priv->icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1204 "accessories-dictionary",
1205 48,
1206 0,
1207 NULL((void*)0));
1208
1209 /* force first draw */
1210 gdict_applet_draw (applet);
1211
1212 /* force retrieval of the configuration from settings */
1213 gdict_applet_set_source_name (applet, NULL((void*)0));
1214 gdict_applet_set_defbox_font (applet, NULL((void*)0));
1215 gdict_applet_set_print_font (applet, NULL((void*)0));
1216}
1217
1218static const GtkActionEntry gdict_applet_menu_actions[] = {
1219 {"DictionaryLookup", "edit-find", N_("_Look Up Selected Text")("_Look Up Selected Text"),
1220 NULL((void*)0), NULL((void*)0),
1221 G_CALLBACK (gdict_applet_cmd_lookup)((GCallback) (gdict_applet_cmd_lookup)) },
1222 {"DictionaryClear", "edit-clear", N_("Cl_ear")("Cl_ear"),
1223 NULL((void*)0), NULL((void*)0),
1224 G_CALLBACK (gdict_applet_cmd_clear)((GCallback) (gdict_applet_cmd_clear)) },
1225 {"DictionaryPrint", "document-print", N_("_Print")("_Print"),
1226 NULL((void*)0), NULL((void*)0),
1227 G_CALLBACK (gdict_applet_cmd_print)((GCallback) (gdict_applet_cmd_print)) },
1228 {"DictionarySave", "document-save", N_("_Save")("_Save"),
1229 NULL((void*)0), NULL((void*)0),
1230 G_CALLBACK (gdict_applet_cmd_save)((GCallback) (gdict_applet_cmd_save)) },
1231 {"DictionaryPreferences", "document-properties", N_("Preferences")("Preferences"),
1232 NULL((void*)0), NULL((void*)0),
1233 G_CALLBACK (gdict_applet_cmd_preferences)((GCallback) (gdict_applet_cmd_preferences)) },
1234 {"DictionaryHelp", "help-browser", N_("_Help")("_Help"),
1235 NULL((void*)0), NULL((void*)0),
1236 G_CALLBACK (gdict_applet_cmd_help)((GCallback) (gdict_applet_cmd_help)) },
1237 {"DictionaryAbout", "help-about", N_("_About")("_About"),
1238 NULL((void*)0), NULL((void*)0),
1239 G_CALLBACK (gdict_applet_cmd_about)((GCallback) (gdict_applet_cmd_about)) },
1240};
1241
1242static gboolean
1243gdict_applet_factory (MatePanelApplet *applet,
1244 const gchar *iid,
1245 gpointer data)
1246{
1247 gboolean retval = FALSE(0);
1248 GdictApplet *dictionary_applet = GDICT_APPLET (applet)((((GdictApplet*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gdict_applet_get_type ()))))))
;
1249 GdictAppletPrivate *priv = dictionary_applet->priv;
1250
1251 if (((!strcmp (iid, "DictionaryApplet"))) && gdict_create_data_dir ())
1252 {
1253 /* Set up the menu */
1254 priv->context_menu_action_group = gtk_action_group_new ("Dictionary Applet Actions");
1255#ifdef ENABLE_NLS1
1256 gtk_action_group_set_translation_domain(priv->context_menu_action_group,
1257 GETTEXT_PACKAGE"mate-utils");
1258#endif /* ENABLE_NLS */
1259 gtk_action_group_add_actions(priv->context_menu_action_group,
1260 gdict_applet_menu_actions,
1261 G_N_ELEMENTS (gdict_applet_menu_actions)(sizeof (gdict_applet_menu_actions) / sizeof ((gdict_applet_menu_actions
)[0]))
,
1262 applet);
1263 mate_panel_applet_setup_menu_from_file (applet,
1264 PKGDATADIR"/usr/local/share/mate-dictionary" "/dictionary-applet-menu.xml",
1265 priv->context_menu_action_group);
1266
1267 gtk_widget_show (GTK_WIDGET (applet)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((applet)), ((gtk_widget_get_type ()))))))
);
1268
1269 /* set the menu items insensitive */
1270 gdict_applet_set_menu_items_sensitive (dictionary_applet, FALSE(0));
1271
1272 retval = TRUE(!(0));
1273 }
1274
1275 return retval;
1276}
1277
1278/* this defines the main () for the applet */
1279PANEL_APPLET_FACTORY ("DictionaryAppletFactory",int main(int argc, char *argv[]) { GOptionContext *context; GError
*error; int retval; do { bindtextdomain ("mate-utils", "/usr/local/share/locale"
); bind_textdomain_codeset ("mate-utils", "UTF-8"); if ((!(0)
)) textdomain ("mate-utils"); } while (0); context = g_option_context_new
(""); g_option_context_add_group (context, gtk_get_option_group
((!(0)))); error = ((void*)0); if (!g_option_context_parse (context
, &argc, &argv, &error)) { if (error) { g_printerr
("Cannot parse arguments: %s.\n", error->message); g_error_free
(error); } else { g_printerr ("Cannot parse arguments.\n"); }
g_option_context_free (context); return 1; } gtk_init (&
argc, &argv); retval = mate_panel_applet_factory_main ("DictionaryAppletFactory"
,(!(0)), (gdict_applet_get_type ()), gdict_applet_factory, ((
void*)0)); g_option_context_free (context); return retval; }
1280 GDICT_TYPE_APPLET,int main(int argc, char *argv[]) { GOptionContext *context; GError
*error; int retval; do { bindtextdomain ("mate-utils", "/usr/local/share/locale"
); bind_textdomain_codeset ("mate-utils", "UTF-8"); if ((!(0)
)) textdomain ("mate-utils"); } while (0); context = g_option_context_new
(""); g_option_context_add_group (context, gtk_get_option_group
((!(0)))); error = ((void*)0); if (!g_option_context_parse (context
, &argc, &argv, &error)) { if (error) { g_printerr
("Cannot parse arguments: %s.\n", error->message); g_error_free
(error); } else { g_printerr ("Cannot parse arguments.\n"); }
g_option_context_free (context); return 1; } gtk_init (&
argc, &argv); retval = mate_panel_applet_factory_main ("DictionaryAppletFactory"
,(!(0)), (gdict_applet_get_type ()), gdict_applet_factory, ((
void*)0)); g_option_context_free (context); return retval; }
1281 "mate-dictionary-applet",int main(int argc, char *argv[]) { GOptionContext *context; GError
*error; int retval; do { bindtextdomain ("mate-utils", "/usr/local/share/locale"
); bind_textdomain_codeset ("mate-utils", "UTF-8"); if ((!(0)
)) textdomain ("mate-utils"); } while (0); context = g_option_context_new
(""); g_option_context_add_group (context, gtk_get_option_group
((!(0)))); error = ((void*)0); if (!g_option_context_parse (context
, &argc, &argv, &error)) { if (error) { g_printerr
("Cannot parse arguments: %s.\n", error->message); g_error_free
(error); } else { g_printerr ("Cannot parse arguments.\n"); }
g_option_context_free (context); return 1; } gtk_init (&
argc, &argv); retval = mate_panel_applet_factory_main ("DictionaryAppletFactory"
,(!(0)), (gdict_applet_get_type ()), gdict_applet_factory, ((
void*)0)); g_option_context_free (context); return retval; }
1282 gdict_applet_factory,int main(int argc, char *argv[]) { GOptionContext *context; GError
*error; int retval; do { bindtextdomain ("mate-utils", "/usr/local/share/locale"
); bind_textdomain_codeset ("mate-utils", "UTF-8"); if ((!(0)
)) textdomain ("mate-utils"); } while (0); context = g_option_context_new
(""); g_option_context_add_group (context, gtk_get_option_group
((!(0)))); error = ((void*)0); if (!g_option_context_parse (context
, &argc, &argv, &error)) { if (error) { g_printerr
("Cannot parse arguments: %s.\n", error->message); g_error_free
(error); } else { g_printerr ("Cannot parse arguments.\n"); }
g_option_context_free (context); return 1; } gtk_init (&
argc, &argv); retval = mate_panel_applet_factory_main ("DictionaryAppletFactory"
,(!(0)), (gdict_applet_get_type ()), gdict_applet_factory, ((
void*)0)); g_option_context_free (context); return retval; }
1283 NULL)int main(int argc, char *argv[]) { GOptionContext *context; GError
*error; int retval; do { bindtextdomain ("mate-utils", "/usr/local/share/locale"
); bind_textdomain_codeset ("mate-utils", "UTF-8"); if ((!(0)
)) textdomain ("mate-utils"); } while (0); context = g_option_context_new
(""); g_option_context_add_group (context, gtk_get_option_group
((!(0)))); error = ((void*)0); if (!g_option_context_parse (context
, &argc, &argv, &error)) { if (error) { g_printerr
("Cannot parse arguments: %s.\n", error->message); g_error_free
(error); } else { g_printerr ("Cannot parse arguments.\n"); }
g_option_context_free (context); return 1; } gtk_init (&
argc, &argv); retval = mate_panel_applet_factory_main ("DictionaryAppletFactory"
,(!(0)), (gdict_applet_get_type ()), gdict_applet_factory, ((
void*)0)); g_option_context_free (context); return retval; }
;
1284
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-91f89a.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-91f89a.html new file mode 100644 index 00000000..08d94d64 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-91f89a.html @@ -0,0 +1,2007 @@ + + + +baobab.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:baobab/src/baobab.c
Warning:line 1216, column 9
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name baobab.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 static -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/baobab/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D PREFIX="/usr/local" -D SYSCONFDIR="/usr/local/etc" -D LIBDIR="/usr/local/lib" -D DATADIR="/usr/local/share" -D BAOBAB_PIX_DIR="/usr/local/share/mate-disk-usage-analyzer/pixmaps/" -D MATELOCALEDIR="/usr/local/share/locale" -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/libgtop-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/baobab/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c baobab.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2005-2006 Fabio Marzocca <thesaltydog@gmail.com>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H1
21#include <config.h>
22#endif
23
24#include <gtk/gtk.h>
25#include <glib/gi18n.h>
26#include <gio/gio.h>
27#include <glibtop.h>
28
29#include "baobab.h"
30#include "baobab-scan.h"
31#include "baobab-treeview.h"
32#include "baobab-utils.h"
33#include "callbacks.h"
34#include "baobab-prefs.h"
35
36#include "baobab-treemap.h"
37#include "baobab-ringschart.h"
38
39#define BAOBAB_UI_RESOURCE"/org/mate/disk-usage-analyzer/baobab-main-window.ui" "/org/mate/disk-usage-analyzer/baobab-main-window.ui"
40#define GET_WIDGET(x)(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, (x)))), ((gtk_widget_get_type
())))))))
(GTK_WIDGET (gtk_builder_get_object (baobab.main_ui, (x)))((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, (x)))), ((gtk_widget_get_type
()))))))
)
41#define GET_ACTION(x)(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, (x)))), ((gtk_action_get_type
())))))))
(GTK_ACTION (gtk_builder_get_object (baobab.main_ui, (x)))((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, (x)))), ((gtk_action_get_type
()))))))
)
42#define GET_TOGGLE_ACTION(x)(((((GtkToggleAction*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gtk_builder_get_object (baobab.main_ui, (x)
))), ((gtk_toggle_action_get_type ())))))))
(GTK_TOGGLE_ACTION (gtk_builder_get_object (baobab.main_ui, (x)))((((GtkToggleAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, (x)))), ((gtk_toggle_action_get_type
()))))))
)
43
44static void push_iter_in_stack (GtkTreeIter *);
45static GtkTreeIter pop_iter_from_stack (void);
46
47BaobabApplication baobab;
48
49static gint currentdepth = 0;
50static GtkTreeIter currentiter;
51static GtkTreeIter firstiter;
52static GQueue *iterstack = NULL((void*)0);
53
54enum {
55 DND_TARGET_URI_LIST
56};
57
58static GtkTargetEntry dnd_target_list[] = {
59 { "text/uri-list", 0, DND_TARGET_URI_LIST },
60};
61
62static gboolean
63scan_is_local (GFile *file)
64{
65 gchar *uri_scheme;
66 gboolean ret = FALSE(0);
67
68 uri_scheme = g_file_get_uri_scheme (file);
69 if (g_ascii_strcasecmp(uri_scheme,"file") == 0)
70 ret = TRUE(!(0));
71
72 g_free (uri_scheme);
73
74 return ret;
75}
76
77void
78baobab_set_busy (gboolean busy)
79{
80 static GdkCursor *busy_cursor = NULL((void*)0);
81 GdkCursor *cursor = NULL((void*)0);
82 GdkWindow *window;
83 GdkDisplay *display;
84
85 window = gtk_widget_get_window (baobab.window);
86
87 if (busy == TRUE(!(0))) {
88 if (!busy_cursor && window) {
89 display = gtk_widget_get_display (baobab.window);
90 busy_cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
91 }
92 cursor = busy_cursor;
93
94 gtk_widget_show (baobab.spinner);
95 gtk_spinner_start (GTK_SPINNER (baobab.spinner)((((GtkSpinner*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.spinner)), ((gtk_spinner_get_type ()))))))
);
96
97 baobab_chart_freeze_updates (baobab.rings_chart);
98 baobab_chart_freeze_updates (baobab.treemap_chart);
99
100 gtk_widget_set_sensitive (baobab.chart_type_combo, FALSE(0));
101 }
102 else {
103 gtk_widget_hide (baobab.spinner);
104 gtk_spinner_stop (GTK_SPINNER (baobab.spinner)((((GtkSpinner*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.spinner)), ((gtk_spinner_get_type ()))))))
);
105
106 baobab_chart_thaw_updates (baobab.rings_chart);
107 baobab_chart_thaw_updates (baobab.treemap_chart);
108
109 gtk_widget_set_sensitive (baobab.chart_type_combo, TRUE(!(0)));
110 }
111
112 /* change the cursor */
113 if (window) {
114 gdk_window_set_cursor (window, cursor);
115 }
116}
117
118static void
119set_drop_target (GtkWidget *target, gboolean active) {
120 if (active) {
121 gtk_drag_dest_set (GTK_WIDGET (target)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((target)), ((gtk_widget_get_type ()))))))
,
122 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
123 dnd_target_list,
124 G_N_ELEMENTS (dnd_target_list)(sizeof (dnd_target_list) / sizeof ((dnd_target_list)[0])),
125 GDK_ACTION_COPY);
126 } else {
127 gtk_drag_dest_unset (target);
128 }
129}
130
131/* menu & toolbar sensitivity */
132static void
133check_menu_sens (gboolean scanning)
134{
135 gboolean has_current_location;
136
137 if (scanning) {
138 while (gtk_events_pending ())
139 gtk_main_iteration ();
140
141 baobab_set_statusbar (_("Scanning...")gettext ("Scanning..."));
142 gtk_action_set_sensitive (GET_ACTION ("expand_all")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("expand_all")))
), ((gtk_action_get_type ())))))))
, TRUE(!(0)));
143 gtk_action_set_sensitive (GET_ACTION ("collapse_all")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("collapse_all")
))), ((gtk_action_get_type ())))))))
, TRUE(!(0)));
144 }
145
146 has_current_location = baobab.current_location != NULL((void*)0);
147
148 gtk_action_set_sensitive (GET_ACTION ("menuscanhome")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menuscanhome")
))), ((gtk_action_get_type ())))))))
, !scanning);
149 gtk_action_set_sensitive (GET_ACTION ("menuallfs")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menuallfs"))))
, ((gtk_action_get_type ())))))))
, !scanning);
150 gtk_action_set_sensitive (GET_ACTION ("menuscandir")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menuscandir"))
)), ((gtk_action_get_type ())))))))
, !scanning);
151 gtk_action_set_sensitive (GET_ACTION ("menustop")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menustop")))),
((gtk_action_get_type ())))))))
, scanning);
152 gtk_action_set_sensitive (GET_ACTION ("menurescan")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menurescan")))
), ((gtk_action_get_type ())))))))
, !scanning && has_current_location);
153 gtk_action_set_sensitive (GET_ACTION ("preferenze1")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("preferenze1"))
)), ((gtk_action_get_type ())))))))
, !scanning);
154 gtk_action_set_sensitive (GET_ACTION ("menu_scan_rem")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menu_scan_rem"
)))), ((gtk_action_get_type ())))))))
, !scanning);
155 gtk_action_set_sensitive (GET_ACTION ("ck_allocated")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("ck_allocated")
))), ((gtk_action_get_type ())))))))
, !scanning && baobab.is_local);
156
157 gtk_widget_set_sensitive (GET_WIDGET ("tbscanhome")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tbscanhome")))
), ((gtk_widget_get_type ())))))))
, !scanning);
158 gtk_widget_set_sensitive (GET_WIDGET ("tbscanall")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tbscanall"))))
, ((gtk_widget_get_type ())))))))
, !scanning);
159 gtk_widget_set_sensitive (GET_WIDGET ("tbscandir")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tbscandir"))))
, ((gtk_widget_get_type ())))))))
, !scanning);
160 gtk_widget_set_sensitive (GET_WIDGET ("tbstop")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tbstop")))), (
(gtk_widget_get_type ())))))))
, scanning);
161 gtk_widget_set_sensitive (GET_WIDGET ("tbrescan")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tbrescan")))),
((gtk_widget_get_type ())))))))
, !scanning && has_current_location);
162 gtk_widget_set_sensitive (GET_WIDGET ("tb_scan_remote")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("tb_scan_remote"
)))), ((gtk_widget_get_type ())))))))
, !scanning);
163}
164
165static void
166check_drop_targets (gboolean scanning)
167{
168 set_drop_target (baobab.rings_chart, !scanning);
169 set_drop_target (baobab.treemap_chart, !scanning);
170}
171
172static void
173update_scan_label (void)
174{
175 gchar *markup;
176 gchar *total;
177 gchar *used;
178 gchar *available;
179
180 total = g_format_size (baobab.fs.total);
181 used = g_format_size (baobab.fs.used);
182 available = g_format_size (baobab.fs.avail);
183
184 /* Translators: these are labels for disk space */
185 markup = g_markup_printf_escaped ("<small>%s <b>%s</b> (%s %s %s %s)</small>",
186 _("Total filesystem capacity:")gettext ("Total filesystem capacity:"), total,
187 _("used:")gettext ("used:"), used,
188 _("available:")gettext ("available:"), available);
189
190 g_free (total);
191 g_free (used);
192 g_free (available);
193
194 gtk_label_set_markup (GTK_LABEL (GET_WIDGET ("label1"))((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) (((((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("label1")))), (
(gtk_widget_get_type ()))))))))), ((gtk_label_get_type ()))))
))
, markup);
195 g_free (markup);
196}
197
198void
199baobab_update_filesystem (void)
200{
201 baobab_get_filesystem (&baobab.fs);
202 update_scan_label ();
203}
204
205void
206baobab_scan_location (GFile *file)
207{
208 GtkToggleAction *ck_allocated;
209
210 if (!baobab_check_dir (file))
211 return;
212
213 if (iterstack !=NULL((void*)0))
214 return;
215
216 if (baobab.current_location)
217 g_object_unref (baobab.current_location);
218 baobab.current_location = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
219
220 baobab.STOP_SCANNING = FALSE(0);
221 baobab_set_busy (TRUE(!(0)));
222 check_menu_sens (TRUE(!(0)));
223 check_drop_targets (TRUE(!(0)));
224 gtk_tree_store_clear (baobab.model);
225 currentdepth = -1; /* flag */
226 iterstack = g_queue_new ();
227
228 /* check if the file system is local or remote */
229 baobab.is_local = scan_is_local (file);
230 ck_allocated = GET_TOGGLE_ACTION ("ck_allocated")(((((GtkToggleAction*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gtk_builder_get_object (baobab.main_ui, ("ck_allocated"
)))), ((gtk_toggle_action_get_type ())))))))
;
231 if (!baobab.is_local) {
232 gtk_toggle_action_set_active (ck_allocated, FALSE(0));
233 gtk_action_set_sensitive (GTK_ACTION (ck_allocated)((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ck_allocated)), ((gtk_action_get_type ()))))))
, FALSE(0));
234 baobab.show_allocated = FALSE(0);
235 }
236 else {
237 gtk_action_set_sensitive (GTK_ACTION (ck_allocated)((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ck_allocated)), ((gtk_action_get_type ()))))))
, TRUE(!(0)));
238 }
239
240 baobab_scan_execute (file);
241
242 /* set statusbar, percentage and allocated/normal size */
243 baobab_set_statusbar (_("Calculating percentage bars...")gettext ("Calculating percentage bars..."));
244 gtk_tree_model_foreach (GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
,
245 show_bars,
246 NULL((void*)0));
247
248 baobab_chart_set_max_depth (baobab.rings_chart, baobab.model_max_depth);
249 baobab_chart_set_max_depth (baobab.treemap_chart, baobab.model_max_depth);
250
251 baobab_set_busy (FALSE(0));
252 check_menu_sens (FALSE(0));
253 check_drop_targets (FALSE(0));
254 baobab_set_statusbar (_("Ready")gettext ("Ready"));
255
256 gtk_tree_view_columns_autosize (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
);
257 baobab.STOP_SCANNING = TRUE(!(0));
258 g_queue_free (iterstack);
259 iterstack = NULL((void*)0);
260 baobab.CONTENTS_CHANGED_DELAYED = FALSE(0);
261}
262
263void
264baobab_scan_home (void)
265{
266 GFile *file;
267
268 file = g_file_new_for_path (g_get_home_dir ());
269 baobab_scan_location (file);
270 g_object_unref (file);
271}
272
273void
274baobab_scan_root (void)
275{
276 GFile *file;
277
278 file = g_file_new_for_uri ("file:///");
279 baobab_scan_location (file);
280 g_object_unref (file);
281}
282
283void
284baobab_rescan_current_dir (void)
285{
286 g_return_if_fail (baobab.current_location != NULL)do { if ((baobab.current_location != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "baobab.current_location != NULL"
); return; } } while (0)
;
287
288 baobab_update_filesystem ();
289
290 g_object_ref (baobab.current_location)((__typeof__ (baobab.current_location)) (g_object_ref) (baobab
.current_location))
;
291 baobab_scan_location (baobab.current_location);
292 g_object_unref (baobab.current_location);
293}
294
295void
296baobab_stop_scan (void)
297{
298 baobab.STOP_SCANNING = TRUE(!(0));
299
300 baobab_set_statusbar (_("Calculating percentage bars...")gettext ("Calculating percentage bars..."));
301 gtk_tree_model_foreach (GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
,
302 show_bars, NULL((void*)0));
303 gtk_tree_view_columns_autosize (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
);
304}
305
306/*
307 * pre-fills model during scanning
308 */
309static void
310prefill_model (struct chan_data *data)
311{
312 GtkTreeIter iter, iterparent;
313 char *name;
314 char *str;
315
316 if (currentdepth == -1) {
317 gtk_tree_store_append (baobab.model, &iter, NULL((void*)0));
318 firstiter = iter;
319 }
320 else if (data->depth == 1) {
321 GtkTreePath *path;
322
323 gtk_tree_store_append (baobab.model, &iter, &firstiter);
324 path = gtk_tree_model_get_path (GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
,
325 &firstiter);
326 gtk_tree_view_expand_row (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
,
327 path, FALSE(0));
328 gtk_tree_path_free (path);
329 }
330 else if (data->depth > currentdepth) {
331 gtk_tree_store_append (baobab.model, &iter, &currentiter);
332 }
333 else if (data->depth == currentdepth) {
334 gtk_tree_model_iter_parent ((GtkTreeModel *) baobab.model,
335 &iterparent, &currentiter);
336 gtk_tree_store_append (baobab.model, &iter, &iterparent);
337 }
338 else if (data->depth < currentdepth) {
339 GtkTreeIter tempiter;
340 gint i;
341 iter = currentiter;
342 for (i = 0; i <= (currentdepth - data->depth); i++) {
343 gtk_tree_model_iter_parent ((GtkTreeModel *)
344 baobab.model,
345 &tempiter, &iter);
346 iter = tempiter;
347 }
348 gtk_tree_store_append (baobab.model, &iter, &tempiter);
349 }
350
351 currentdepth = data->depth;
352 push_iter_in_stack (&iter);
353 currentiter = iter;
354
355 /* in case filenames contains gmarkup */
356 name = g_markup_escape_text (data->display_name, -1);
357
358 str = g_strdup_printf ("<small><i>%s</i></small>", _("Scanning...")gettext ("Scanning..."));
359
360 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
, TRUE(!(0)));
361 gtk_tree_store_set (baobab.model, &iter,
362 COL_DIR_NAME, name,
363 COL_H_PARSENAME, "",
364 COL_H_ELEMENTS, -1,
365 COL_H_PERC, -1.0,
366 COL_DIR_SIZE, str,
367 COL_ELEMENTS, str, -1);
368
369 g_free (name);
370 g_free (str);
371
372 while (gtk_events_pending ()) {
373 gtk_main_iteration ();
374 }
375}
376
377static void
378first_row (void)
379{
380 char *size;
381 gdouble perc;
382 char *label;
383
384 GtkTreeIter root_iter;
385
386 gchar *capacity_label, *capacity_size;
387
388 gtk_tree_store_append (baobab.model, &root_iter, NULL((void*)0));
389
390 capacity_size = g_format_size (baobab.fs.total);
391
392 capacity_label = g_strdup (_("Total filesystem capacity"))g_strdup_inline (gettext ("Total filesystem capacity"));
393 gtk_tree_store_set (baobab.model, &root_iter,
394 COL_DIR_NAME, capacity_label,
395 COL_H_PARSENAME, "",
396 COL_H_PERC, 100.0,
397 COL_DIR_SIZE, capacity_size,
398 COL_H_SIZE, baobab.fs.total,
399 COL_H_ALLOCSIZE, baobab.fs.total,
400 COL_H_ELEMENTS, -1, -1);
401 g_free (capacity_label);
402 g_free (capacity_size);
403
404 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
, FALSE(0));
405 gtk_tree_store_append (baobab.model, &firstiter, &root_iter);
406
407 size = g_format_size (baobab.fs.used);
408
409 if (baobab.fs.total == 0 && baobab.fs.used == 0) {
410 perc = 100.0;
411 } else {
412 g_assert (baobab.fs.total != 0)do { if (baobab.fs.total != 0) ; else g_assertion_message_expr
(((gchar*) 0), "baobab.c", 412, ((const char*) (__func__)), "baobab.fs.total != 0"
); } while (0)
;
413 perc = ((gdouble) baobab.fs.used * 100) / (gdouble) baobab.fs.total;
414 }
415
416 label = g_strdup (_("Total filesystem usage"))g_strdup_inline (gettext ("Total filesystem usage"));
417 gtk_tree_store_set (baobab.model, &firstiter,
418 COL_DIR_NAME, label,
419 COL_H_PARSENAME, "",
420 COL_H_PERC, perc,
421 COL_DIR_SIZE, size,
422 COL_H_SIZE, baobab.fs.used,
423 COL_H_ALLOCSIZE, baobab.fs.used,
424 COL_H_ELEMENTS, -1, -1);
425
426 g_free (size);
427 g_free (label);
428
429 gtk_tree_view_expand_all (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
);
430}
431
432/* fills model during scanning */
433void
434baobab_fill_model (struct chan_data *data)
435{
436 GtkTreeIter iter;
437 GString *hardlinks;
438 GString *elements;
439 char *name;
440 char *size;
441 char *alloc_size;
442
443 if (data->elements == -1) {
444 prefill_model (data);
445 return;
446 }
447
448 iter = pop_iter_from_stack ();
449
450 /* in case filenames contains gmarkup */
451 name = g_markup_escape_text (data->display_name, -1);
452
453 hardlinks = g_string_new ("");
454 if (data->tempHLsize > 0) {
455 size = g_format_size (data->tempHLsize);
456
457 g_string_assign (hardlinks, "<i>(");
458 g_string_append (hardlinks, _("contains hardlinks for:"))(__builtin_constant_p (gettext ("contains hardlinks for:")) ?
__extension__ ({ const char * const __val = (gettext ("contains hardlinks for:"
)); g_string_append_len_inline (hardlinks, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (hardlinks, gettext ("contains hardlinks for:"
), (gssize) -1))
;
459 g_string_append (hardlinks, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (hardlinks, __val,
(__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)
)) : (gssize) -1); }) : g_string_append_len_inline (hardlinks
, " ", (gssize) -1))
;
460 g_string_append (hardlinks, size)(__builtin_constant_p (size) ? __extension__ ({ const char * const
__val = (size); g_string_append_len_inline (hardlinks, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (hardlinks
, size, (gssize) -1))
;
461 g_string_append (hardlinks, ")</i>")(__builtin_constant_p (")</i>") ? __extension__ ({ const
char * const __val = (")</i>"); g_string_append_len_inline
(hardlinks, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(hardlinks, ")</i>", (gssize) -1))
;
462 g_free (size);
463 }
464
465 elements = g_string_new ("");
466 g_string_printf (elements,
467 ngettext ("%5d item", "%5d items",
468 data->elements), data->elements);
469
470 size = g_format_size (data->size);
471 alloc_size = g_format_size (data->alloc_size);
472
473 gtk_tree_store_set (baobab.model, &iter,
474 COL_DIR_NAME, name,
475 COL_H_PARSENAME, data->parse_name,
476 COL_H_PERC, -1.0,
477 COL_DIR_SIZE,
478 baobab.show_allocated ? alloc_size : size,
479 COL_H_SIZE, data->size,
480 COL_ELEMENTS, elements->str,
481 COL_H_ELEMENTS, data->elements,
482 COL_HARDLINK, hardlinks->str,
483 COL_H_HARDLINK, data->tempHLsize,
484 COL_H_ALLOCSIZE, data->alloc_size, -1);
485
486 while (gtk_events_pending ()) {
487 gtk_main_iteration ();
488 }
489
490 g_string_free (hardlinks, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(hardlinks), ((!(0)))) : g_string_free_and_steal (hardlinks))
: (g_string_free) ((hardlinks), ((!(0)))))
;
491 g_string_free (elements, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(elements), ((!(0)))) : g_string_free_and_steal (elements)) :
(g_string_free) ((elements), ((!(0)))))
;
492 g_free (name);
493 g_free (size);
494 g_free (alloc_size);
495}
496
497void
498push_iter_in_stack (GtkTreeIter *iter)
499{
500 g_queue_push_head (iterstack, iter->user_data3);
501 g_queue_push_head (iterstack, iter->user_data2);
502 g_queue_push_head (iterstack, iter->user_data);
503 g_queue_push_head (iterstack, GINT_TO_POINTER (iter->stamp)((gpointer) (glong) (iter->stamp)));
504}
505
506GtkTreeIter
507pop_iter_from_stack (void)
508{
509 GtkTreeIter iter;
510
511 iter.stamp = GPOINTER_TO_INT (g_queue_pop_head (iterstack))((gint) (glong) (g_queue_pop_head (iterstack)));
512 iter.user_data = g_queue_pop_head (iterstack);
513 iter.user_data2 = g_queue_pop_head (iterstack);
514 iter.user_data3 = g_queue_pop_head (iterstack);
515
516 return iter;
517}
518
519gboolean
520baobab_is_excluded_location (GFile *file)
521{
522 gboolean ret = FALSE(0);
523 GSList *l;
524
525 g_return_val_if_fail (file != NULL, FALSE)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "file != NULL"); return
((0)); } } while (0)
;
526
527 for (l = baobab.excluded_locations; l != NULL((void*)0); l = l->next) {
528 if (g_file_equal (l->data, file)) {
529 ret = TRUE(!(0));
530 break;
531 }
532 }
533
534 return ret;
535}
536
537static void
538volume_changed (GVolumeMonitor *volume_monitor,
539 GVolume *volume,
540 gpointer user_data)
541{
542 /* filesystem has changed (mounted or unmounted device) */
543 baobab_update_filesystem ();
544}
545
546static void
547home_contents_changed (GFileMonitor *file_monitor,
548 GFile *child,
549 GFile *other_file,
550 GFileMonitorEvent event_type,
551 gpointer user_data)
552
553{
554 gchar *excluding;
555
556 if (baobab.CONTENTS_CHANGED_DELAYED)
557 return;
558
559 excluding = g_file_get_basename (child);
560 if (strcmp (excluding, ".recently-used") == 0 ||
561 strcmp (excluding, ".mate2_private") == 0 ||
562 strcmp (excluding, ".xsession-errors") == 0 ||
563 strcmp (excluding, ".bash_history") == 0) {
564 g_free (excluding);
565 return;
566 }
567 g_free (excluding);
568
569 baobab.CONTENTS_CHANGED_DELAYED = TRUE(!(0));
570}
571
572static void
573monitor_volume (void)
574{
575 baobab.monitor_vol = g_volume_monitor_get ();
576
577 g_signal_connect (baobab.monitor_vol, "volume_changed",g_signal_connect_data ((baobab.monitor_vol), ("volume_changed"
), (((GCallback) (volume_changed))), (((void*)0)), ((void*)0)
, (GConnectFlags) 0)
578 G_CALLBACK (volume_changed), NULL)g_signal_connect_data ((baobab.monitor_vol), ("volume_changed"
), (((GCallback) (volume_changed))), (((void*)0)), ((void*)0)
, (GConnectFlags) 0)
;
579}
580
581static void
582monitor_home (gboolean enable)
583{
584 if (enable && baobab.monitor_home == NULL((void*)0)) {
585 GFile *file;
586 GError *error = NULL((void*)0);
587
588 file = g_file_new_for_path (g_get_home_dir ());
589 baobab.monitor_home = g_file_monitor_directory (file, 0, NULL((void*)0), &error);
590 g_object_unref (file);
591
592 if (!baobab.monitor_home) {
593 message (_("Could not initialize monitoring")gettext ("Could not initialize monitoring"),
594 _("Changes to your home folder will not be monitored.")gettext ("Changes to your home folder will not be monitored."
)
,
595 GTK_MESSAGE_WARNING, NULL((void*)0));
596 g_print ("homedir:%s\n", error->message);
597 g_error_free (error);
598 }
599 else {
600 g_signal_connect (baobab.monitor_home,g_signal_connect_data ((baobab.monitor_home), ("changed"), ((
(GCallback) (home_contents_changed))), (((void*)0)), ((void*)
0), (GConnectFlags) 0)
601 "changed",g_signal_connect_data ((baobab.monitor_home), ("changed"), ((
(GCallback) (home_contents_changed))), (((void*)0)), ((void*)
0), (GConnectFlags) 0)
602 G_CALLBACK (home_contents_changed),g_signal_connect_data ((baobab.monitor_home), ("changed"), ((
(GCallback) (home_contents_changed))), (((void*)0)), ((void*)
0), (GConnectFlags) 0)
603 NULL)g_signal_connect_data ((baobab.monitor_home), ("changed"), ((
(GCallback) (home_contents_changed))), (((void*)0)), ((void*)
0), (GConnectFlags) 0)
;
604 }
605 }
606 else if (!enable && baobab.monitor_home != NULL((void*)0)) {
607 g_file_monitor_cancel (baobab.monitor_home);
608 g_object_unref (baobab.monitor_home);
609 baobab.monitor_home = NULL((void*)0);
610 }
611}
612
613void
614baobab_set_statusbar (const gchar *text)
615{
616 gtk_statusbar_pop (GTK_STATUSBAR (baobab.statusbar)((((GtkStatusbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.statusbar)), ((gtk_statusbar_get_type ()))))))
, 1);
617 gtk_statusbar_push (GTK_STATUSBAR (baobab.statusbar)((((GtkStatusbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.statusbar)), ((gtk_statusbar_get_type ()))))))
, 1, text);
618
619 while (gtk_events_pending ())
620 gtk_main_iteration ();
621}
622
623static void
624toolbar_reconfigured_cb (GtkToolItem *item,
625 GtkWidget *spinner)
626{
627 GtkToolbarStyle style;
628 GtkIconSize size;
629
630 style = gtk_tool_item_get_toolbar_style (item);
631
632 if (style == GTK_TOOLBAR_BOTH)
633 {
634 size = GTK_ICON_SIZE_DIALOG;
635 }
636 else
637 {
638 size = GTK_ICON_SIZE_LARGE_TOOLBAR;
639 }
640
641 gtk_widget_set_size_request (spinner, size, size);
642}
643
644static void
645baobab_create_toolbar (void)
646{
647 GtkWidget *toolbar;
648 GtkToolItem *item;
649 GtkToolItem *separator;
650
651 toolbar = GET_WIDGET ("toolbar1")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("toolbar1")))),
((gtk_widget_get_type ())))))))
;
652 if (toolbar == NULL((void*)0)) {
653 g_printerr ("Could not build toolbar\n");
654 return;
655 }
656
657 baobab.toolbar = toolbar;
658
659 separator = gtk_separator_tool_item_new ();
660 gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (separator)((((GtkSeparatorToolItem*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((separator)), ((gtk_separator_tool_item_get_type
()))))))
, FALSE(0));
661 gtk_tool_item_set_expand (GTK_TOOL_ITEM (separator)((((GtkToolItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((separator)), ((gtk_tool_item_get_type ()))))))
, TRUE(!(0)));
662 gtk_container_add (GTK_CONTAINER (toolbar)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_container_get_type ()))))))
, GTK_WIDGET (separator)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((separator)), ((gtk_widget_get_type ()))))))
);
663 gtk_widget_show (GTK_WIDGET (separator)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((separator)), ((gtk_widget_get_type ()))))))
);
664
665 baobab.spinner = gtk_spinner_new ();
666 item = gtk_tool_item_new ();
667 gtk_container_add (GTK_CONTAINER (item)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_container_get_type ()))))))
, baobab.spinner);
668 gtk_container_add (GTK_CONTAINER (toolbar)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_container_get_type ()))))))
, GTK_WIDGET (item)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_widget_get_type ()))))))
);
669 gtk_widget_show (GTK_WIDGET (item)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_widget_get_type ()))))))
);
670
671 g_signal_connect (item, "toolbar-reconfigured",g_signal_connect_data ((item), ("toolbar-reconfigured"), (((GCallback
) (toolbar_reconfigured_cb))), (baobab.spinner), ((void*)0), (
GConnectFlags) 0)
672 G_CALLBACK (toolbar_reconfigured_cb), baobab.spinner)g_signal_connect_data ((item), ("toolbar-reconfigured"), (((GCallback
) (toolbar_reconfigured_cb))), (baobab.spinner), ((void*)0), (
GConnectFlags) 0)
;
673 toolbar_reconfigured_cb (item, baobab.spinner);
674
675 g_settings_bind (baobab.ui_settings,
676 BAOBAB_SETTINGS_TOOLBAR_VISIBLE"toolbar-visible",
677 baobab.toolbar, "visible",
678 G_SETTINGS_BIND_DEFAULT);
679 g_settings_bind (baobab.ui_settings,
680 BAOBAB_SETTINGS_TOOLBAR_VISIBLE"toolbar-visible",
681 GET_TOGGLE_ACTION ("view_tb")(((((GtkToggleAction*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gtk_builder_get_object (baobab.main_ui, ("view_tb"
)))), ((gtk_toggle_action_get_type ())))))))
, "active",
682 G_SETTINGS_BIND_DEFAULT);
683
684}
685
686static void
687baobab_create_statusbar (void)
688{
689 baobab.statusbar = GET_WIDGET ("statusbar1")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("statusbar1")))
), ((gtk_widget_get_type ())))))))
;
690 if (baobab.statusbar == NULL((void*)0)) {
691 g_printerr ("Could not build statusbar\n");
692 return;
693 }
694
695 g_settings_bind (baobab.ui_settings,
696 BAOBAB_SETTINGS_STATUSBAR_VISIBLE"statusbar-visible",
697 baobab.statusbar, "visible",
698 G_SETTINGS_BIND_DEFAULT);
699 g_settings_bind (baobab.ui_settings,
700 BAOBAB_SETTINGS_STATUSBAR_VISIBLE"statusbar-visible",
701 GET_TOGGLE_ACTION ("view_sb")(((((GtkToggleAction*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gtk_builder_get_object (baobab.main_ui, ("view_sb"
)))), ((gtk_toggle_action_get_type ())))))))
, "active",
702 G_SETTINGS_BIND_DEFAULT);
703}
704
705static void
706baobab_settings_subfoldertips_changed (GSettings *settings,
707 const gchar *key,
708 gpointer user_data)
709{
710 gboolean visible;
711
712 visible = g_settings_get_boolean (settings, key);
713 baobab_ringschart_set_subfoldertips_enabled (baobab.rings_chart, visible);
714}
715
716static void
717baobab_set_excluded_locations (gchar **uris)
718{
719 gint i;
720
721 g_slist_free_full (baobab.excluded_locations, g_object_unref);
722 baobab.excluded_locations = NULL((void*)0);
723 for (i = 0; uris[i] != NULL((void*)0); ++i) {
724 baobab.excluded_locations = g_slist_prepend (baobab.excluded_locations,
725 g_file_new_for_uri (uris[i]));
726 }
727}
728
729static void
730store_excluded_locations (void)
731{
732 GSList *l;
733 GPtrArray *uris;
734
735 uris = g_ptr_array_new ();
736
737 for (l = baobab.excluded_locations; l != NULL((void*)0); l = l->next) {
738 g_ptr_array_add (uris, g_file_get_uri (l->data));
739 }
740
741 g_ptr_array_add (uris, NULL((void*)0));
742
743 g_settings_set_strv (baobab.prefs_settings,
744 BAOBAB_SETTINGS_EXCLUDED_URIS"excluded-uris",
745 (const gchar *const *) uris->pdata);
746
747 g_ptr_array_free (uris, TRUE(!(0)));
748}
749
750static void
751sanity_check_excluded_locations (void)
752{
753 GFile *root;
754 GSList *l;
755
756 /* Make sure the root dir is not excluded */
757 root = g_file_new_for_uri ("file:///");
758
759 for (l = baobab.excluded_locations; l != NULL((void*)0); l = l->next) {
760 if (g_file_equal (l->data, root)) {
761 baobab.excluded_locations = g_slist_delete_link (baobab.excluded_locations, l);
762 store_excluded_locations ();
763 break;
764 }
765 }
766
767 g_object_unref (root);
768}
769
770static void
771excluded_uris_changed (GSettings *settings,
772 const gchar *key,
773 gpointer user_data)
774{
775 gchar **uris;
776
777 uris = g_settings_get_strv (settings, key);
778 baobab_set_excluded_locations (uris);
779 g_strfreev (uris);
780
781 baobab_update_filesystem ();
782
783 gtk_tree_store_clear (baobab.model);
784 first_row ();
785}
786
787static void
788baobab_setup_excluded_locations (void)
789{
790 gchar **uris;
791
792 g_signal_connect (baobab.prefs_settings,g_signal_connect_data ((baobab.prefs_settings), ("changed::" "excluded-uris"
), (((GCallback) (excluded_uris_changed))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
793 "changed::" BAOBAB_SETTINGS_EXCLUDED_URIS,g_signal_connect_data ((baobab.prefs_settings), ("changed::" "excluded-uris"
), (((GCallback) (excluded_uris_changed))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
794 G_CALLBACK (excluded_uris_changed),g_signal_connect_data ((baobab.prefs_settings), ("changed::" "excluded-uris"
), (((GCallback) (excluded_uris_changed))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
795 NULL)g_signal_connect_data ((baobab.prefs_settings), ("changed::" "excluded-uris"
), (((GCallback) (excluded_uris_changed))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
796
797 uris = g_settings_get_strv (baobab.prefs_settings,
798 BAOBAB_SETTINGS_EXCLUDED_URIS"excluded-uris");
799 baobab_set_excluded_locations (uris);
800 g_strfreev (uris);
801
802 sanity_check_excluded_locations ();
803}
804
805static void
806baobab_settings_monitor_home_changed (GSettings *settings,
807 const gchar *key,
808 gpointer user_data)
809{
810 gboolean enable;
811
812 enable = g_settings_get_boolean (settings, key);
813
814 monitor_home (enable);
815}
816
817static void
818baobab_setup_monitors (void)
819{
820 gboolean enable;
821
822 monitor_volume ();
823
824 g_signal_connect (baobab.prefs_settings,g_signal_connect_data ((baobab.prefs_settings), ("changed::" "monitor-home"
), (((GCallback) (baobab_settings_monitor_home_changed))), ((
(void*)0)), ((void*)0), (GConnectFlags) 0)
825 "changed::" BAOBAB_SETTINGS_MONITOR_HOME,g_signal_connect_data ((baobab.prefs_settings), ("changed::" "monitor-home"
), (((GCallback) (baobab_settings_monitor_home_changed))), ((
(void*)0)), ((void*)0), (GConnectFlags) 0)
826 G_CALLBACK (baobab_settings_monitor_home_changed),g_signal_connect_data ((baobab.prefs_settings), ("changed::" "monitor-home"
), (((GCallback) (baobab_settings_monitor_home_changed))), ((
(void*)0)), ((void*)0), (GConnectFlags) 0)
827 NULL)g_signal_connect_data ((baobab.prefs_settings), ("changed::" "monitor-home"
), (((GCallback) (baobab_settings_monitor_home_changed))), ((
(void*)0)), ((void*)0), (GConnectFlags) 0)
;
828
829 enable = g_settings_get_boolean (baobab.prefs_settings,
830 BAOBAB_SETTINGS_MONITOR_HOME"monitor-home");
831
832 monitor_home (enable);
833}
834
835static void
836baobab_init (void)
837{
838 GError *error = NULL((void*)0);
839
840 /* FileSystem usage */
841 baobab_get_filesystem (&baobab.fs);
842
843 /* Load the UI */
844 baobab.main_ui = gtk_builder_new ();
845 if (gtk_builder_add_from_resource (baobab.main_ui, BAOBAB_UI_RESOURCE"/org/mate/disk-usage-analyzer/baobab-main-window.ui", &error) == 0) {
846 g_object_unref (baobab.main_ui);
847 g_critical ("Unable to load the user interface file: %s", error->message);
848 g_error_free (error);
849 exit (1);
850 }
851
852 gtk_builder_connect_signals (baobab.main_ui, NULL((void*)0));
853
854 /* Settings */
855 baobab.ui_settings = g_settings_new (BAOBAB_UI_SETTINGS_SCHEMA"org.mate.disk-usage-analyzer.ui");
856 baobab.prefs_settings = g_settings_new (BAOBAB_PREFS_SETTINGS_SCHEMA"org.mate.disk-usage-analyzer.preferences");
857
858 /* Misc */
859 baobab.CONTENTS_CHANGED_DELAYED = FALSE(0);
860 baobab.STOP_SCANNING = TRUE(!(0));
861 baobab.show_allocated = TRUE(!(0));
862 baobab.is_local = TRUE(!(0));
863
864 baobab_setup_excluded_locations ();
865
866 baobab_create_toolbar ();
867 baobab_create_statusbar ();
868 baobab_setup_monitors ();
869
870 g_signal_connect (baobab.ui_settings, "changed::" BAOBAB_SETTINGS_SUBFLSTIPS_VISIBLE,g_signal_connect_data ((baobab.ui_settings), ("changed::" "subfoldertips-visible"
), ((GCallback) baobab_settings_subfoldertips_changed), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
871 (GCallback) baobab_settings_subfoldertips_changed, NULL)g_signal_connect_data ((baobab.ui_settings), ("changed::" "subfoldertips-visible"
), ((GCallback) baobab_settings_subfoldertips_changed), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
872}
873
874static void
875baobab_shutdown (void)
876{
877 if (baobab.current_location) {
878 g_object_unref (baobab.current_location);
879 }
880
881 if (baobab.monitor_vol) {
882 g_object_unref (baobab.monitor_vol);
883 }
884
885 if (baobab.monitor_home) {
886 g_file_monitor_cancel (baobab.monitor_home);
887 g_object_unref (baobab.monitor_home);
888 }
889
890 g_free (baobab.selected_path);
891
892 g_slist_free_full (baobab.excluded_locations, g_object_unref);
893
894 if (baobab.ui_settings) {
895 g_object_unref (baobab.ui_settings);
896 }
897
898 if (baobab.prefs_settings) {
899 g_object_unref (baobab.prefs_settings);
900 }
901}
902
903static BaobabChartMenu *
904create_context_menu (void)
905{
906 BaobabChartMenu *menu = NULL((void*)0);
907
908 baobab.chart_menu = g_new0 (BaobabChartMenu, 1)((BaobabChartMenu *) g_malloc0_n ((1), sizeof (BaobabChartMenu
)))
;
909 menu = baobab.chart_menu;
910
911 menu->widget = gtk_menu_new ();
912
913 menu->up_item = gtk_image_menu_item_new_with_label (_("Move to parent folder")gettext ("Move to parent folder"));
914 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->up_item)((((GtkImageMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((menu->up_item)), ((gtk_image_menu_item_get_type
()))))))
,
915 gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_MENU));
916
917 menu->zoom_in_item = gtk_image_menu_item_new_with_label (_("Zoom in")gettext ("Zoom in")) ;
918 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->zoom_in_item)((((GtkImageMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((menu->zoom_in_item)), ((gtk_image_menu_item_get_type
()))))))
,
919 gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_MENU));
920
921 menu->zoom_out_item = gtk_image_menu_item_new_with_label (_("Zoom out")gettext ("Zoom out"));
922 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->zoom_out_item)((((GtkImageMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((menu->zoom_out_item)), ((gtk_image_menu_item_get_type
()))))))
,
923 gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_MENU));
924
925 menu->snapshot_item = gtk_image_menu_item_new_with_label (_("Save screenshot")gettext ("Save screenshot"));
926 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->snapshot_item)((((GtkImageMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((menu->snapshot_item)), ((gtk_image_menu_item_get_type
()))))))
,
927 gtk_image_new_from_icon_name ("applets-screenshooter", GTK_ICON_SIZE_MENU));
928
929 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
930 menu->up_item);
931 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
932 gtk_separator_menu_item_new ());
933 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
934 menu->zoom_in_item);
935 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
936 menu->zoom_out_item);
937 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
938 gtk_separator_menu_item_new ());
939 gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_shell_get_type ()))))))
,
940 menu->snapshot_item);
941
942 /* connect signals */
943 g_signal_connect (menu->up_item, "activate",g_signal_connect_data ((menu->up_item), ("activate"), (((GCallback
) (on_move_upwards_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
944 G_CALLBACK (on_move_upwards_cb), NULL)g_signal_connect_data ((menu->up_item), ("activate"), (((GCallback
) (on_move_upwards_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
945 g_signal_connect (menu->zoom_in_item, "activate",g_signal_connect_data ((menu->zoom_in_item), ("activate"),
(((GCallback) (on_zoom_in_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
946 G_CALLBACK (on_zoom_in_cb), NULL)g_signal_connect_data ((menu->zoom_in_item), ("activate"),
(((GCallback) (on_zoom_in_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
947 g_signal_connect (menu->zoom_out_item, "activate",g_signal_connect_data ((menu->zoom_out_item), ("activate")
, (((GCallback) (on_zoom_out_cb))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
948 G_CALLBACK (on_zoom_out_cb), NULL)g_signal_connect_data ((menu->zoom_out_item), ("activate")
, (((GCallback) (on_zoom_out_cb))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
949 g_signal_connect (menu->snapshot_item, "activate",g_signal_connect_data ((menu->snapshot_item), ("activate")
, (((GCallback) (on_chart_snapshot_cb))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
950 G_CALLBACK (on_chart_snapshot_cb), NULL)g_signal_connect_data ((menu->snapshot_item), ("activate")
, (((GCallback) (on_chart_snapshot_cb))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
951
952 gtk_widget_show_all (menu->widget);
953
954 return menu;
955}
956
957static void
958on_chart_item_activated (BaobabChart *chart, GtkTreeIter *iter)
959{
960 GtkTreePath *path;
961
962 path = gtk_tree_model_get_path (GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
, iter);
963
964 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
, path))
965 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
, path);
966
967 gtk_tree_view_set_cursor (GTK_TREE_VIEW (baobab.tree_view)((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.tree_view)), ((gtk_tree_view_get_type ()))))))
,
968 path, NULL((void*)0), FALSE(0));
969 gtk_tree_path_free (path);
970}
971
972static gboolean
973on_chart_button_release (BaobabChart *chart,
974 GdkEventButton *event,
975 gpointer data)
976{
977 if (baobab_chart_is_frozen (baobab.current_chart))
978 return FALSE(0);
979
980 if (event->button== 3) /* right button */
981 {
982 GtkTreePath *root_path;
983 BaobabChartMenu *menu;
984
985 root_path = baobab_chart_get_root (baobab.current_chart);
986
987 menu = baobab.chart_menu;
988 gtk_widget_set_sensitive (menu->up_item,
989 ((root_path != NULL((void*)0)) &&
990 (gtk_tree_path_get_depth (root_path) > 1)));
991 gtk_widget_set_sensitive (menu->zoom_in_item,
992 baobab_chart_can_zoom_in (baobab.current_chart));
993 gtk_widget_set_sensitive (menu->zoom_out_item,
994 baobab_chart_can_zoom_out (baobab.current_chart));
995
996 /* show the menu */
997 gtk_menu_popup_at_pointer (GTK_MENU (menu->widget)((((GtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu->widget)), ((gtk_menu_get_type ()))))))
,
998 (const GdkEvent*) event);
999
1000 gtk_tree_path_free (root_path);
1001 }
1002
1003 return FALSE(0);
1004}
1005
1006static void
1007drag_data_received_handl (GtkWidget *widget,
1008 GdkDragContext *context,
1009 gint x,
1010 gint y,
1011 GtkSelectionData *selection_data,
1012 guint target_type,
1013 guint time,
1014 gpointer data)
1015{
1016 GFile *gf = NULL((void*)0);
1017
1018 /* set "gf" if we got some valid data */
1019 if ((selection_data != NULL((void*)0)) &&
1020 (gtk_selection_data_get_length (selection_data) >= 0) &&
1021 (target_type == DND_TARGET_URI_LIST)) {
1022 gchar **uri_list;
1023 uri_list = g_uri_list_extract_uris ((const gchar *) gtk_selection_data_get_data (selection_data));
1024 /* check list is 1 item long */
1025 if (uri_list != NULL((void*)0) && uri_list[0] != NULL((void*)0) && uri_list[1] == NULL((void*)0)) {
1026 gf = g_file_new_for_uri (uri_list[0]);
1027 }
1028 g_strfreev (uri_list);
1029 }
1030
1031 /* success if "gf" has been set */
1032 if (gf != NULL((void*)0)) {
1033 /* finish drop before beginning scan, as the drag-drop can
1034 probably time out */
1035 gtk_drag_finish (context, TRUE(!(0)), FALSE(0), time);
1036 baobab_scan_location (gf);
1037 g_object_unref (gf);
1038 } else {
1039 gtk_drag_finish (context, FALSE(0), FALSE(0), time);
1040 }
1041}
1042
1043static void
1044set_active_chart (GtkWidget *chart)
1045{
1046 if (baobab.current_chart != chart) {
1047 if (baobab.current_chart) {
1048 baobab_chart_freeze_updates (baobab.current_chart);
1049
1050 g_object_ref (baobab.current_chart)((__typeof__ (baobab.current_chart)) (g_object_ref) (baobab.current_chart
))
;
1051 gtk_container_remove (GTK_CONTAINER (baobab.chart_frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_frame)), ((gtk_container_get_type ()))))))
,
1052 baobab.current_chart);
1053 }
1054
1055 gtk_container_add (GTK_CONTAINER (baobab.chart_frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_frame)), ((gtk_container_get_type ()))))))
, chart);
1056 g_object_unref (chart);
1057
1058 baobab_chart_thaw_updates (chart);
1059
1060 baobab.current_chart = chart;
1061
1062 gtk_widget_show_all (baobab.chart_frame);
1063
1064 g_settings_set_string (baobab.ui_settings,
1065 BAOBAB_SETTINGS_ACTIVE_CHART"active-chart",
1066 baobab.current_chart == baobab.rings_chart ? "rings" : "treemap");
1067 }
1068}
1069
1070static void
1071on_chart_type_change (GtkWidget *combo, gpointer user_data)
1072{
1073 GtkWidget *chart;
1074 gint active;
1075
1076 active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((combo)), ((gtk_combo_box_get_type ()))))))
);
1077
1078 switch (active) {
1079 case 0:
1080 chart = baobab.rings_chart;
1081 break;
1082 case 1:
1083 chart = baobab.treemap_chart;
1084 break;
1085 default:
1086 g_return_if_reached ()do { g_log (((gchar*) 0), G_LOG_LEVEL_CRITICAL, "file %s: line %d (%s): should not be reached"
, "baobab.c", 1086, ((const char*) (__func__))); return; } while
(0)
;
1087 }
1088
1089 set_active_chart (chart);
1090}
1091
1092static void
1093initialize_charts (void)
1094{
1095 GtkWidget *hpaned_main;
1096 GtkWidget *hbox1;
1097 char *saved_chart;
1098 gboolean visible;
1099
1100 baobab.chart_frame = gtk_frame_new (NULL((void*)0));
1101 gtk_frame_set_label_align (GTK_FRAME (baobab.chart_frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_frame)), ((gtk_frame_get_type ()))))))
, 0.0, 0.0);
1102 gtk_frame_set_shadow_type (GTK_FRAME (baobab.chart_frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_frame)), ((gtk_frame_get_type ()))))))
, GTK_SHADOW_IN);
1103
1104 hpaned_main = GET_WIDGET ("hpaned_main")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("hpaned_main"))
)), ((gtk_widget_get_type ())))))))
;
1105 gtk_paned_pack2 (GTK_PANED (hpaned_main)((((GtkPaned*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hpaned_main)), ((gtk_paned_get_type ()))))))
,
1106 baobab.chart_frame, TRUE(!(0)), TRUE(!(0)));
1107 gtk_paned_set_position (GTK_PANED (hpaned_main)((((GtkPaned*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hpaned_main)), ((gtk_paned_get_type ()))))))
, 480);
1108
1109 baobab.chart_type_combo = gtk_combo_box_text_new ();
1110 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (baobab.chart_type_combo)((((GtkComboBoxText*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_type_combo)), ((gtk_combo_box_text_get_type
()))))))
,
1111 _("View as Rings Chart")gettext ("View as Rings Chart"));
1112 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (baobab.chart_type_combo)((((GtkComboBoxText*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_type_combo)), ((gtk_combo_box_text_get_type
()))))))
,
1113 _("View as Treemap Chart")gettext ("View as Treemap Chart"));
1114 gtk_widget_show (baobab.chart_type_combo);
1115 g_signal_connect (baobab.chart_type_combo,g_signal_connect_data ((baobab.chart_type_combo), ("changed")
, (((GCallback) (on_chart_type_change))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
1116 "changed",g_signal_connect_data ((baobab.chart_type_combo), ("changed")
, (((GCallback) (on_chart_type_change))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
1117 G_CALLBACK (on_chart_type_change), NULL)g_signal_connect_data ((baobab.chart_type_combo), ("changed")
, (((GCallback) (on_chart_type_change))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
1118
1119 hbox1 = GET_WIDGET ("hbox1")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("hbox1")))), ((
gtk_widget_get_type ())))))))
;
1120 gtk_container_add (GTK_CONTAINER (hbox1)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox1)), ((gtk_container_get_type ()))))))
, baobab.chart_type_combo);
1121 gtk_box_set_spacing (GTK_BOX (hbox1)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox1)), ((gtk_box_get_type ()))))))
, 50);
1122 gtk_box_set_child_packing (GTK_BOX (hbox1)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox1)), ((gtk_box_get_type ()))))))
,
1123 baobab.chart_type_combo,
1124 FALSE(0),
1125 TRUE(!(0)),
1126 0, GTK_PACK_END);
1127
1128 baobab.chart_menu = create_context_menu ();
1129
1130 /* Baobab's Treemap Chart */
1131 baobab.treemap_chart = baobab_treemap_new ();
1132 baobab_chart_set_model_with_columns (baobab.treemap_chart,
1133 GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
,
1134 COL_DIR_NAME,
1135 COL_DIR_SIZE,
1136 COL_H_PARSENAME,
1137 COL_H_PERC,
1138 COL_H_ELEMENTS,
1139 NULL((void*)0));
1140 baobab_chart_set_max_depth (baobab.treemap_chart, 1);
1141 g_signal_connect (baobab.treemap_chart, "item_activated",g_signal_connect_data ((baobab.treemap_chart), ("item_activated"
), (((GCallback) (on_chart_item_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1142 G_CALLBACK (on_chart_item_activated), NULL)g_signal_connect_data ((baobab.treemap_chart), ("item_activated"
), (((GCallback) (on_chart_item_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1143 g_signal_connect (baobab.treemap_chart, "button-release-event",g_signal_connect_data ((baobab.treemap_chart), ("button-release-event"
), (((GCallback) (on_chart_button_release))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1144 G_CALLBACK (on_chart_button_release), NULL)g_signal_connect_data ((baobab.treemap_chart), ("button-release-event"
), (((GCallback) (on_chart_button_release))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1145 g_signal_connect (baobab.treemap_chart, "drag-data-received",g_signal_connect_data ((baobab.treemap_chart), ("drag-data-received"
), (((GCallback) (drag_data_received_handl))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1146 G_CALLBACK (drag_data_received_handl), NULL)g_signal_connect_data ((baobab.treemap_chart), ("drag-data-received"
), (((GCallback) (drag_data_received_handl))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1147 gtk_widget_show (baobab.treemap_chart);
1148 g_object_ref_sink (baobab.treemap_chart)((__typeof__ (baobab.treemap_chart)) (g_object_ref_sink) (baobab
.treemap_chart))
;
1149 baobab_chart_freeze_updates (baobab.treemap_chart);
1150
1151 /* Baobab's Rings Chart */
1152 baobab.rings_chart = (GtkWidget *) baobab_ringschart_new ();
1153 baobab_chart_set_model_with_columns (baobab.rings_chart,
1154 GTK_TREE_MODEL (baobab.model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.model)), ((gtk_tree_model_get_type ()))))))
,
1155 COL_DIR_NAME,
1156 COL_DIR_SIZE,
1157 COL_H_PARSENAME,
1158 COL_H_PERC,
1159 COL_H_ELEMENTS,
1160 NULL((void*)0));
1161
1162 visible = g_settings_get_boolean (baobab.ui_settings,
1163 BAOBAB_SETTINGS_SUBFLSTIPS_VISIBLE"subfoldertips-visible");
1164 baobab_ringschart_set_subfoldertips_enabled (baobab.rings_chart, visible);
1165
1166 baobab_chart_set_max_depth (baobab.rings_chart, 1);
1167 g_signal_connect (baobab.rings_chart, "item_activated",g_signal_connect_data ((baobab.rings_chart), ("item_activated"
), (((GCallback) (on_chart_item_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1168 G_CALLBACK (on_chart_item_activated), NULL)g_signal_connect_data ((baobab.rings_chart), ("item_activated"
), (((GCallback) (on_chart_item_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1169 g_signal_connect (baobab.rings_chart, "button-release-event",g_signal_connect_data ((baobab.rings_chart), ("button-release-event"
), (((GCallback) (on_chart_button_release))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1170 G_CALLBACK (on_chart_button_release), NULL)g_signal_connect_data ((baobab.rings_chart), ("button-release-event"
), (((GCallback) (on_chart_button_release))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1171 g_signal_connect (baobab.rings_chart, "drag-data-received",g_signal_connect_data ((baobab.rings_chart), ("drag-data-received"
), (((GCallback) (drag_data_received_handl))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1172 G_CALLBACK (drag_data_received_handl), NULL)g_signal_connect_data ((baobab.rings_chart), ("drag-data-received"
), (((GCallback) (drag_data_received_handl))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1173 gtk_widget_show (baobab.rings_chart);
1174 g_object_ref_sink (baobab.rings_chart)((__typeof__ (baobab.rings_chart)) (g_object_ref_sink) (baobab
.rings_chart))
;
1175 baobab_chart_freeze_updates (baobab.rings_chart);
1176
1177 saved_chart = g_settings_get_string (baobab.ui_settings,
1178 BAOBAB_SETTINGS_ACTIVE_CHART"active-chart");
1179
1180 if (0 == g_ascii_strcasecmp (saved_chart, "treemap")) {
1181 set_active_chart (baobab.treemap_chart);
1182 gtk_combo_box_set_active (GTK_COMBO_BOX (baobab.chart_type_combo)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_type_combo)), ((gtk_combo_box_get_type ()))
))))
, 1);
1183 } else {
1184 set_active_chart (baobab.rings_chart);
1185 gtk_combo_box_set_active (GTK_COMBO_BOX (baobab.chart_type_combo)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.chart_type_combo)), ((gtk_combo_box_get_type ()))
))))
, 0);
1186 }
1187
1188 g_free (saved_chart);
1189
1190 check_drop_targets (FALSE(0));
1191}
1192
1193void
1194baobab_quit ()
1195{
1196 baobab_stop_scan ();
1197 gtk_main_quit ();
1198}
1199
1200static gboolean
1201start_proc_on_command_line (GFile *file)
1202{
1203 baobab_scan_location (file);
1204
1205 return FALSE(0);
1206}
1207
1208static gboolean
1209show_version (const gchar *option_name,
1210 const gchar *value,
1211 gpointer data,
1212 GError **error)
1213{
1214 g_print("%s %s\n", g_get_application_name (), VERSION"1.27.0");
1215 exit (0);
1216 return TRUE(!(0)); /* It's just good form */
This statement is never executed
1217}
1218
1219int
1220main (int argc, char *argv[])
1221{
1222 gchar **directories = NULL((void*)0);
1223 const GOptionEntry options[] = {
1224 {"version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version, N_("Show version")("Show version"), NULL((void*)0)},
1225 {G_OPTION_REMAINING"", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &directories, NULL((void*)0), N_("[DIRECTORY]")("[DIRECTORY]")},
1226 { NULL((void*)0), 0, 0, G_OPTION_ARG_NONE, NULL((void*)0), NULL((void*)0), NULL((void*)0) }
1227 };
1228 GOptionContext *context;
1229 GError *error = NULL((void*)0);
1230
1231#ifdef ENABLE_NLS1
1232 bindtextdomain (GETTEXT_PACKAGE"mate-utils", MATELOCALEDIR"/usr/local/share/locale");
1233 bind_textdomain_codeset (GETTEXT_PACKAGE"mate-utils", "UTF-8");
1234 textdomain (GETTEXT_PACKAGE"mate-utils");
1235#endif /* ENABLE_NLS */
1236
1237 g_set_application_name (_("Disk Usage Analyzer")gettext ("Disk Usage Analyzer"));
1238
1239 context = g_option_context_new (NULL((void*)0));
1240 g_option_context_set_ignore_unknown_options (context, FALSE(0));
1241 g_option_context_set_help_enabled (context, TRUE(!(0)));
1242 g_option_context_add_main_entries(context, options, GETTEXT_PACKAGE"mate-utils");
1243 g_option_context_add_group (context, gtk_get_option_group (TRUE(!(0))));
1244
1245 g_option_context_parse (context, &argc, &argv, &error);
1246
1247 if (error) {
1248 g_critical ("Unable to parse option: %s", error->message);
1249 g_error_free (error);
1250 g_option_context_free (context);
1251
1252 exit (1);
1253 }
1254 g_option_context_free (context);
1255
1256 if (directories && directories[0] && directories[1]) {
1257 g_critical (_("Too many arguments. Only one directory can be specified.")gettext ("Too many arguments. Only one directory can be specified."
)
);
1258 exit (1);
1259 }
1260
1261 glibtop_init ();
1262
1263 gtk_window_set_default_icon_name ("mate-disk-usage-analyzer");
1264
1265 baobab_init ();
1266
1267 if (baobab.fs.total == 0) {
1268 GtkWidget *dialog;
1269
1270 dialog = gtk_message_dialog_new (NULL((void*)0),
1271 GTK_DIALOG_DESTROY_WITH_PARENT,
1272 GTK_MESSAGE_ERROR,
1273 GTK_BUTTONS_CLOSE,
1274 _("Could not detect any mount point.")gettext ("Could not detect any mount point."));
1275 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog)((((GtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((gtk_message_dialog_get_type ())
)))))
,
1276 _("Without mount points disk usage cannot be analyzed.")gettext ("Without mount points disk usage cannot be analyzed."
)
);
1277 gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
1278 gtk_widget_destroy (dialog);
1279 goto closing;
1280 }
1281
1282 check_menu_sens (FALSE(0));
1283 update_scan_label ();
1284
1285 baobab.window = GET_WIDGET ("baobab_window")(((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("baobab_window"
)))), ((gtk_widget_get_type ())))))))
;
1286 gtk_window_set_position (GTK_WINDOW (baobab.window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((baobab.window)), ((gtk_window_get_type ()))))))
,
1287 GTK_WIN_POS_CENTER);
1288
1289 baobab.tree_view = create_directory_treeview ();
1290
1291 gtk_action_set_sensitive (GET_ACTION ("menurescan")(((((GtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (baobab.main_ui, ("menurescan")))
), ((gtk_action_get_type ())))))))
, FALSE(0));
1292
1293 /* set allocated space checkbox */
1294 gtk_toggle_action_set_active (GET_TOGGLE_ACTION ("ck_allocated")(((((GtkToggleAction*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gtk_builder_get_object (baobab.main_ui, ("ck_allocated"
)))), ((gtk_toggle_action_get_type ())))))))
,
1295 baobab.show_allocated);
1296
1297 gtk_widget_show (baobab.window);
1298
1299 first_row ();
1300 baobab_set_statusbar (_("Ready")gettext ("Ready"));
1301
1302 initialize_charts ();
1303
1304 /* commandline */
1305 if (directories && directories[0]) {
1306 GFile *file;
1307
1308 file = g_file_new_for_commandline_arg (directories[0]);
1309
1310 /* start processing the dir specified on the
1311 * command line as soon as we enter the main loop */
1312 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE200,
1313 (GSourceFunc) start_proc_on_command_line,
1314 file,
1315 g_object_unref);
1316 }
1317 g_strfreev (directories);
1318
1319 gtk_main ();
1320
1321 closing:
1322 baobab_shutdown ();
1323
1324 glibtop_close ();
1325
1326 return 0;
1327}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-9aacf9.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-9aacf9.html new file mode 100644 index 00000000..23431c84 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-9aacf9.html @@ -0,0 +1,2047 @@ + + + +mate-screenshot.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-screenshot/src/mate-screenshot.c
Warning:line 1362, column 13
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-screenshot.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 static -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/mate-screenshot/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I . -I . -D MATELOCALEDIR="/usr/local/share/locale" -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -D _REENTRANT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-screenshot/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c mate-screenshot.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
2 * Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
3 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
4 * Copyright (C) 2012-2021 MATE Developers
5 *
6 * This file is part of MATE Utils.
7 *
8 * MATE Utils is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * MATE Utils is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#ifdef HAVE_CONFIG_H1
23#include <config.h>
24#endif
25
26#include <gdk/gdkx.h>
27#include <gdk/gdkkeysyms.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <errno(*__errno_location ()).h>
35#ifdef ENABLE_NLS1
36#include <locale.h>
37#endif /* ENABLE_NLS */
38#include <glib/gi18n.h>
39#include <gio/gio.h>
40#include <pwd.h>
41#include <X11/Xutil.h>
42#include <canberra-gtk.h>
43
44#include "screenshot-shadow.h"
45#include "screenshot-utils.h"
46#include "screenshot-save.h"
47#include "screenshot-dialog.h"
48#include "screenshot-xfer.h"
49
50#define SCREENSHOOTER_ICON"applets-screenshooter" "applets-screenshooter"
51
52#define MATE_SCREENSHOT_SCHEMA"org.mate.screenshot" "org.mate.screenshot"
53#define INCLUDE_BORDER_KEY"include-border" "include-border"
54#define INCLUDE_POINTER_KEY"include-pointer" "include-pointer"
55#define LAST_SAVE_DIRECTORY_KEY"last-save-directory" "last-save-directory"
56#define BORDER_EFFECT_KEY"border-effect" "border-effect"
57#define DELAY_KEY"delay" "delay"
58#define CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences" "org.mate.caja.preferences"
59
60enum
61{
62 COLUMN_NICK,
63 COLUMN_LABEL,
64 COLUMN_ID,
65
66 N_COLUMNS
67};
68
69typedef enum {
70 SCREENSHOT_EFFECT_NONE,
71 SCREENSHOT_EFFECT_SHADOW,
72 SCREENSHOT_EFFECT_BORDER
73} ScreenshotEffectType;
74
75typedef enum
76{
77 TEST_LAST_DIR = 0,
78 TEST_DESKTOP = 1,
79 TEST_TMP = 2,
80} TestType;
81
82typedef struct
83{
84 char *base_uris[3];
85 char *retval;
86 int iteration;
87 TestType type;
88 GdkWindow *window;
89 GdkRectangle *rectangle;
90} AsyncExistenceJob;
91
92static GdkPixbuf *screenshot = NULL((void*)0);
93
94/* Global variables*/
95static char *last_save_dir = NULL((void*)0);
96static char *temporary_file = NULL((void*)0);
97static gboolean save_immediately = FALSE(0);
98static GSettings *settings = NULL((void*)0);
99static gboolean interactive_arg = FALSE(0);
100static guint delay_arg = 0;
101
102/* Options */
103static gboolean noninteractive_clipboard_arg = FALSE(0);
104static gboolean take_window_shot = FALSE(0);
105static gboolean take_area_shot = FALSE(0);
106static gboolean include_border = FALSE(0);
107static gboolean include_pointer = TRUE(!(0));
108static char *border_effect = NULL((void*)0);
109static guint delay = 0;
110
111/* some local prototypes */
112static void display_help (GtkWindow *parent);
113static void save_done_notification (gpointer data);
114static char *get_desktop_dir (void);
115static void save_options (void);
116
117static GtkWidget *border_check = NULL((void*)0);
118static GtkWidget *effect_combo = NULL((void*)0);
119static GtkWidget *effect_label = NULL((void*)0);
120static GtkWidget *effects_vbox = NULL((void*)0);
121static GtkWidget *delay_hbox = NULL((void*)0);
122
123void loop_dialog_screenshot (void);
124
125static void
126display_help (GtkWindow *parent)
127{
128 GError *error = NULL((void*)0);
129
130 gtk_show_uri_on_window (parent,
131 "help:mate-user-guide/goseditmainmenu-53",
132 gtk_get_current_event_time (),
133 &error);
134
135 if (error)
136 {
137 screenshot_show_gerror_dialog (parent,
138 _("Error loading the help page")gettext ("Error loading the help page"),
139 error);
140 g_error_free (error);
141 }
142}
143
144static void
145interactive_dialog_response_cb (GtkDialog *dialog,
146 gint response,
147 gpointer user_data)
148{
149 switch (response)
150 {
151 case GTK_RESPONSE_HELP:
152 g_signal_stop_emission_by_name (dialog, "response");
153 display_help (GTK_WINDOW (dialog)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_window_get_type ()))))))
);
154 break;
155 default:
156 gtk_widget_hide (GTK_WIDGET (dialog)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_widget_get_type ()))))))
);
157 break;
158 }
159}
160
161#define TARGET_TOGGLE_DESKTOP0 0
162#define TARGET_TOGGLE_WINDOW1 1
163#define TARGET_TOGGLE_AREA2 2
164
165static void
166target_toggled_cb (GtkToggleButton *button,
167 gpointer data)
168{
169 int target_toggle = GPOINTER_TO_INT (data)((gint) (glong) (data));
170
171 if (gtk_toggle_button_get_active (button))
172 {
173 take_window_shot = (target_toggle == TARGET_TOGGLE_WINDOW1);
174 take_area_shot = (target_toggle == TARGET_TOGGLE_AREA2);
175
176 gtk_widget_set_sensitive (border_check, take_window_shot);
177 gtk_widget_set_sensitive (effect_combo, take_window_shot);
178 gtk_widget_set_sensitive (effect_label, take_window_shot);
179
180 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
181 gtk_widget_set_sensitive (effects_vbox, !take_area_shot);
182 }
183}
184
185static void
186delay_spin_value_changed_cb (GtkSpinButton *button)
187{
188 delay = gtk_spin_button_get_value_as_int (button);
189}
190
191static void
192include_border_toggled_cb (GtkToggleButton *button,
193 gpointer data)
194{
195 include_border = gtk_toggle_button_get_active (button);
196}
197
198static void
199include_pointer_toggled_cb (GtkToggleButton *button,
200 gpointer data)
201{
202 include_pointer = gtk_toggle_button_get_active (button);
203}
204
205static void
206effect_combo_changed_cb (GtkComboBox *combo,
207 gpointer user_data)
208{
209 GtkTreeIter iter;
210
211 if (gtk_combo_box_get_active_iter (combo, &iter))
212 {
213 GtkTreeModel *model;
214 gchar *effect;
215
216 model = gtk_combo_box_get_model (combo);
217 gtk_tree_model_get (model, &iter, COLUMN_NICK, &effect, -1);
218
219 g_assert (effect != NULL)do { if (effect != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "mate-screenshot.c", 219, ((const char*) (__func__
)), "effect != NULL"); } while (0)
;
220
221 g_free (border_effect);
222 border_effect = effect; /* gets free'd later */
223 }
224}
225
226static gint
227key_press_cb (GtkWidget* widget, GdkEventKey* event, gpointer data)
228{
229 if (event->keyval == GDK_KEY_F10xffbe)
230 {
231 display_help (GTK_WINDOW (widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gtk_window_get_type ()))))))
);
232 return TRUE(!(0));
233 }
234
235 return FALSE(0);
236}
237
238typedef struct {
239 ScreenshotEffectType id;
240 const gchar *label;
241 const gchar *nick;
242} ScreenshotEffect;
243
244/* Translators:
245 * these are the names of the effects available which will be
246 * displayed inside a combo box in interactive mode for the user
247 * to chooser.
248 */
249static const ScreenshotEffect effects[] = {
250 { SCREENSHOT_EFFECT_NONE, N_("None")("None"), "none" },
251 { SCREENSHOT_EFFECT_SHADOW, N_("Drop shadow")("Drop shadow"), "shadow" },
252 { SCREENSHOT_EFFECT_BORDER, N_("Border")("Border"), "border" }
253};
254
255static guint n_effects = G_N_ELEMENTS (effects)(sizeof (effects) / sizeof ((effects)[0]));
256
257static GtkWidget *
258create_effects_combo (void)
259{
260 GtkWidget *retval;
261 GtkListStore *model;
262 GtkCellRenderer *renderer;
263 gint i;
264
265 model = gtk_list_store_new (N_COLUMNS,
266 G_TYPE_STRING((GType) ((16) << (2))),
267 G_TYPE_STRING((GType) ((16) << (2))),
268 G_TYPE_UINT((GType) ((7) << (2))));
269
270 for (i = 0; i < n_effects; i++)
271 {
272 GtkTreeIter iter;
273
274 gtk_list_store_insert (model, &iter, i);
275 gtk_list_store_set (model, &iter,
276 COLUMN_ID, effects[i].id,
277 COLUMN_LABEL, gettext (effects[i].label),
278 COLUMN_NICK, effects[i].nick,
279 -1);
280 }
281
282 retval = gtk_combo_box_new ();
283 gtk_combo_box_set_model (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
284 GTK_TREE_MODEL (model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((gtk_tree_model_get_type ()))))))
);
285 g_object_unref (model);
286
287 switch (border_effect[0])
288 {
289 case 's': /* shadow */
290 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
291 SCREENSHOT_EFFECT_SHADOW);
292 break;
293 case 'b': /* border */
294 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
295 SCREENSHOT_EFFECT_BORDER);
296 break;
297 case 'n': /* none */
298 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
299 SCREENSHOT_EFFECT_NONE);
300 break;
301 default:
302 break;
303 }
304
305 renderer = gtk_cell_renderer_text_new ();
306 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer, TRUE(!(0)));
307 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer,
308 "text", COLUMN_LABEL,
309 NULL((void*)0));
310
311 g_signal_connect (retval, "changed",g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
312 G_CALLBACK (effect_combo_changed_cb),g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
313 NULL)g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
314
315 return retval;
316}
317
318static void
319create_effects_frame (GtkWidget *outer_vbox,
320 const gchar *frame_title)
321{
322 GtkWidget *main_vbox, *vbox, *hbox;
323 GtkWidget *label;
324 GtkWidget *check;
325 GtkWidget *combo;
326 gchar *title;
327
328 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
329 gtk_widget_set_sensitive (main_vbox, !take_area_shot);
330 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
331 gtk_widget_show (main_vbox);
332 effects_vbox = main_vbox;
333
334 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
335 label = gtk_label_new (title);
336 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
337 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
338 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
339 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
340 gtk_widget_show (label);
341 g_free (title);
342
343 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
344 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
345 gtk_widget_show (hbox);
346
347 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
348 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
349 gtk_widget_set_margin_start (vbox, 12);
350 gtk_widget_show (vbox);
351
352 /** Include pointer **/
353 check = gtk_check_button_new_with_mnemonic (_("Include _pointer")gettext ("Include _pointer"));
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_pointer);
355 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
356 G_CALLBACK (include_pointer_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
357 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
358 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
359 gtk_widget_show (check);
360
361 /** Include window border **/
362 check = gtk_check_button_new_with_mnemonic (_("Include the window _border")gettext ("Include the window _border"));
363 gtk_widget_set_sensitive (check, take_window_shot);
364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_border);
365 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
366 G_CALLBACK (include_border_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
367 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
368 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
369 gtk_widget_show (check);
370 border_check = check;
371
372 /** Effects **/
373 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
374 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
375 gtk_widget_show (hbox);
376
377 label = gtk_label_new_with_mnemonic (_("Apply _effect:")gettext ("Apply _effect:"));
378 gtk_widget_set_sensitive (label, take_window_shot);
379 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
380 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
381 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
382 gtk_widget_show (label);
383 effect_label = label;
384
385 combo = create_effects_combo ();
386 gtk_widget_set_sensitive (combo, take_window_shot);
387 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, combo, FALSE(0), FALSE(0), 0);
388 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, combo);
389 gtk_widget_show (combo);
390 effect_combo = combo;
391}
392
393static void
394create_screenshot_frame (GtkWidget *outer_vbox,
395 const gchar *frame_title)
396{
397 GtkWidget *main_vbox, *vbox, *hbox;
398 GtkWidget *radio;
399 GtkWidget *image;
400 GtkWidget *spin;
401 GtkWidget *label;
402 GtkAdjustment *adjust;
403 GSList *group;
404 gchar *title;
405
406 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
407 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
408 gtk_widget_show (main_vbox);
409
410 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
411 label = gtk_label_new (title);
412 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
413 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
414 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
415 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
416 gtk_widget_show (label);
417 g_free (title);
418
419 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
420 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
421 gtk_widget_show (hbox);
422
423 image = gtk_image_new_from_icon_name (SCREENSHOOTER_ICON"applets-screenshooter",
424 GTK_ICON_SIZE_DIALOG);
425
426 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image, FALSE(0), FALSE(0), 0);
427 gtk_widget_set_valign (image, GTK_ALIGN_START);
428 gtk_widget_show (image);
429
430 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
431 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
432 gtk_widget_show (vbox);
433
434 /** Grab whole desktop **/
435 group = NULL((void*)0);
436 radio = gtk_radio_button_new_with_mnemonic (group,
437 _("Grab the whole _desktop")gettext ("Grab the whole _desktop"));
438 if (take_window_shot || take_area_shot)
439 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, FALSE(0));
440 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
441 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
442 GINT_TO_POINTER (TARGET_TOGGLE_DESKTOP))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
;
443 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
444 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
445 gtk_widget_show (radio);
446
447 /** Grab current window **/
448 radio = gtk_radio_button_new_with_mnemonic (group,
449 _("Grab the current _window")gettext ("Grab the current _window"));
450 if (take_window_shot)
451 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
452 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
453 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
454 GINT_TO_POINTER (TARGET_TOGGLE_WINDOW))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
;
455 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
456 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
457 gtk_widget_show (radio);
458
459 /** Grab area of the desktop **/
460 radio = gtk_radio_button_new_with_mnemonic (group,
461 _("Select _area to grab")gettext ("Select _area to grab"));
462 if (take_area_shot)
463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
464 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
465 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
466 GINT_TO_POINTER (TARGET_TOGGLE_AREA))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
;
467 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
468 gtk_widget_show (radio);
469
470 /** Grab after delay **/
471 delay_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
472 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
473 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, delay_hbox, FALSE(0), FALSE(0), 0);
474 gtk_widget_show (delay_hbox);
475
476 /* translators: this is the first part of the "grab after a
477 * delay of <spin button> seconds".
478 */
479 label = gtk_label_new_with_mnemonic (_("Grab _after a delay of")gettext ("Grab _after a delay of"));
480 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
481 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
482 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
483 gtk_widget_show (label);
484
485 adjust = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) delay,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
486 0.0, 99.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
487 1.0, 1.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
488 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
;
489 spin = gtk_spin_button_new (adjust, 1.0, 0);
490 g_signal_connect (spin, "value-changed",g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
491 G_CALLBACK (delay_spin_value_changed_cb),g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
492 NULL)g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
493 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, spin, FALSE(0), FALSE(0), 0);
494 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, spin);
495 gtk_widget_show (spin);
496
497 /* translators: this is the last part of the "grab after a
498 * delay of <spin button> seconds".
499 */
500 label = gtk_label_new (_("seconds")gettext ("seconds"));
501 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
502 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
503 gtk_box_pack_end (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
504 gtk_widget_show (label);
505}
506
507static GtkWidget *
508create_interactive_dialog (void)
509{
510 GtkWidget *retval;
511 GtkWidget *main_vbox;
512 GtkWidget *content_area;
513
514 retval = gtk_dialog_new ();
515 gtk_window_set_resizable (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, FALSE(0));
516 gtk_container_set_border_width (GTK_CONTAINER (retval)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_container_get_type ()))))))
, 5);
517 content_area = gtk_dialog_get_content_area (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
);
518 gtk_box_set_spacing (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, 2);
519 gtk_window_set_title (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, _("Take Screenshot")gettext ("Take Screenshot"));
520
521 /* main container */
522 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
523 gtk_container_set_border_width (GTK_CONTAINER (main_vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_container_get_type ()))))))
, 5);
524 gtk_box_pack_start (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, main_vbox, TRUE(!(0)), TRUE(!(0)), 0);
525 gtk_widget_show (main_vbox);
526
527 create_screenshot_frame (main_vbox, _("Take Screenshot")gettext ("Take Screenshot"));
528 create_effects_frame (main_vbox, _("Effects")gettext ("Effects"));
529 gtk_dialog_add_buttons (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
,
530 "gtk-help", GTK_RESPONSE_HELP,
531 "gtk-cancel", GTK_RESPONSE_CANCEL,
532 _("Take _Screenshot")gettext ("Take _Screenshot"), GTK_RESPONSE_OK,
533 NULL((void*)0));
534 gtk_dialog_set_default_response (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
535
536 /* we need to block on "response" and keep showing the interactive
537 * dialog in case the user did choose "help"
538 */
539 g_signal_connect (retval, "response",g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
540 G_CALLBACK (interactive_dialog_response_cb),g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
541 NULL)g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
542
543 g_signal_connect (retval, "key-press-event",g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
544 G_CALLBACK(key_press_cb),g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
545 NULL)g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
546
547 return retval;
548}
549
550static void
551save_folder_to_settings (ScreenshotDialog *dialog)
552{
553 char *folder;
554
555 folder = screenshot_dialog_get_folder (dialog);
556 g_settings_set_string (settings,
557 LAST_SAVE_DIRECTORY_KEY"last-save-directory", folder);
558
559 g_free (folder);
560}
561
562static void
563set_recent_entry (ScreenshotDialog *dialog)
564{
565 char *uri, *app_exec = NULL((void*)0);
566 GtkRecentManager *recent;
567 GtkRecentData recent_data;
568 GAppInfo *app;
569 const char *exec_name = NULL((void*)0);
570 static char * groups[2] = { "Graphics", NULL((void*)0) };
571
572 app = g_app_info_get_default_for_type ("image/png", TRUE(!(0)));
573
574 if (!app) {
575 /* return early, as this would be an useless recent entry anyway. */
576 return;
577 }
578
579 uri = screenshot_dialog_get_uri (dialog);
580 recent = gtk_recent_manager_get_default ();
581
582 exec_name = g_app_info_get_executable (app);
583 app_exec = g_strjoin (" ", exec_name, "%u", NULL((void*)0));
584
585 recent_data.display_name = NULL((void*)0);
586 recent_data.description = NULL((void*)0);
587 recent_data.mime_type = "image/png";
588 recent_data.app_name = "MATE Screenshot";
589 recent_data.app_exec = app_exec;
590 recent_data.groups = groups;
591 recent_data.is_private = FALSE(0);
592
593 gtk_recent_manager_add_full (recent, uri, &recent_data);
594
595 g_object_unref (app);
596 g_free (app_exec);
597 g_free (uri);
598}
599
600static void
601error_dialog_response_cb (GtkDialog *d,
602 gint response,
603 ScreenshotDialog *dialog)
604{
605 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
606
607 screenshot_dialog_focus_entry (dialog);
608}
609
610static void
611save_callback (TransferResult result,
612 char *error_message,
613 gpointer data)
614{
615 ScreenshotDialog *dialog = data;
616 GtkWidget *toplevel;
617
618 toplevel = screenshot_dialog_get_toplevel (dialog);
619 screenshot_dialog_set_busy (dialog, FALSE(0));
620
621 if (result == TRANSFER_OK)
622 {
623 save_folder_to_settings (dialog);
624 set_recent_entry (dialog);
625 gtk_widget_destroy (toplevel);
626
627 /* we're done, stop the mainloop now */
628 gtk_main_quit ();
629 }
630 else if (result == TRANSFER_OVERWRITE ||
631 result == TRANSFER_CANCELLED)
632 {
633 /* user has canceled the overwrite dialog or the transfer itself, let him
634 * choose another name.
635 */
636 screenshot_dialog_focus_entry (dialog);
637 }
638 else /* result == TRANSFER_ERROR */
639 {
640 /* we had an error, display a dialog to the user and let him choose
641 * another name/location to save the screenshot.
642 */
643 GtkWidget *error_dialog;
644 char *uri;
645
646 uri = screenshot_dialog_get_uri (dialog);
647 error_dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_window_get_type ()))))))
,
648 GTK_DIALOG_DESTROY_WITH_PARENT,
649 GTK_MESSAGE_ERROR,
650 GTK_BUTTONS_OK,
651 _("Error while saving screenshot")gettext ("Error while saving screenshot"));
652 /* translators: first %s is the file path, second %s is the VFS error */
653 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog)((((GtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((error_dialog)), ((gtk_message_dialog_get_type
()))))))
,
654 _("Impossible to save the screenshot "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
655 "to %s.\n Error was %s.\n Please choose another "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
656 "location and retry.")gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
, uri, error_message);
657 gtk_widget_show (error_dialog);
658 g_signal_connect (error_dialog,g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
659 "response",g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
660 G_CALLBACK (error_dialog_response_cb),g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
661 dialog)g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
662
663 g_free (uri);
664 }
665
666}
667
668static void
669try_to_save (ScreenshotDialog *dialog,
670 const char *target)
671{
672 GFile *source_file, *target_file;
673
674 g_assert (temporary_file)do { if (temporary_file) ; else g_assertion_message_expr (((gchar
*) 0), "mate-screenshot.c", 674, ((const char*) (__func__)), "temporary_file"
); } while (0)
;
675
676 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
677
678 source_file = g_file_new_for_path (temporary_file);
679 target_file = g_file_new_for_uri (target);
680
681 screenshot_xfer_uri (source_file,
682 target_file,
683 screenshot_dialog_get_toplevel (dialog),
684 save_callback, dialog);
685
686 /* screenshot_xfer_uri () holds a ref, so we can unref now */
687 g_object_unref (source_file);
688 g_object_unref (target_file);
689}
690
691static void
692save_done_notification (gpointer data)
693{
694 ScreenshotDialog *dialog = data;
695
696 temporary_file = g_strdup (screenshot_save_get_filename ())g_strdup_inline (screenshot_save_get_filename ());
697 screenshot_dialog_enable_dnd (dialog);
698
699 if (save_immediately)
700 {
701 GtkWidget *toplevel;
702
703 toplevel = screenshot_dialog_get_toplevel (dialog);
704 gtk_dialog_response (GTK_DIALOG (toplevel)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
705 }
706}
707
708static void
709save_screenshot_in_clipboard (GdkDisplay *display, GdkPixbuf *screenshot)
710{
711 GtkClipboard *clipboard =
712 gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
713 gtk_clipboard_set_image (clipboard, screenshot);
714}
715
716static void
717screenshot_dialog_response_cb (GtkDialog *d,
718 gint response_id,
719 ScreenshotDialog *dialog)
720{
721 char *uri;
722
723 if (response_id == GTK_RESPONSE_HELP)
724 {
725 display_help (GTK_WINDOW (d)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_window_get_type ()))))))
);
726 }
727 else if (response_id == SCREENSHOT_RESPONSE_NEW22)
728 {
729 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
730 gtk_main_quit ();
731 interactive_arg = TRUE(!(0));
732 loop_dialog_screenshot();
733 }
734 else if (response_id == GTK_RESPONSE_OK)
735 {
736 uri = screenshot_dialog_get_uri (dialog);
737 if (temporary_file == NULL((void*)0))
738 {
739 save_immediately = TRUE(!(0));
740 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
741 }
742 else
743 {
744 /* we've saved the temporary file, lets try to copy it to the
745 * correct location.
746 */
747 try_to_save (dialog, uri);
748 }
749 g_free (uri);
750 }
751 else if (response_id == SCREENSHOT_RESPONSE_COPY1)
752 {
753 save_screenshot_in_clipboard (gtk_widget_get_display (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
),
754 screenshot_dialog_get_screenshot (dialog));
755 }
756 else /* dialog was canceled */
757 {
758 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
759 gtk_main_quit ();
760 }
761}
762
763static void
764run_dialog (ScreenshotDialog *dialog)
765{
766 GtkWidget *toplevel;
767
768 toplevel = screenshot_dialog_get_toplevel (dialog);
769
770 gtk_widget_show (toplevel);
771
772 g_signal_connect (toplevel,g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
773 "response",g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
774 G_CALLBACK (screenshot_dialog_response_cb),g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
775 dialog)g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
776}
777
778static void
779play_sound_effect (GdkWindow *window)
780{
781 ca_context *c;
782 ca_proplist *p = NULL((void*)0);
783 int res;
784
785 c = ca_gtk_context_get ();
786
787 res = ca_proplist_create (&p);
788 if (res < 0)
789 goto done;
790
791 res = ca_proplist_sets (p, CA_PROP_EVENT_ID"event.id", "screen-capture");
792 if (res < 0)
793 goto done;
794
795 res = ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION"event.description", _("Screenshot taken")gettext ("Screenshot taken"));
796 if (res < 0)
797 goto done;
798
799 if (window != NULL((void*)0))
800 {
801 res = ca_proplist_setf (p,
802 CA_PROP_WINDOW_X11_XID"window.x11.xid",
803 "%lu",
804 (unsigned long) GDK_WINDOW_XID (window)(gdk_x11_window_get_xid (window)));
805 if (res < 0)
806 goto done;
807 }
808
809 ca_context_play_full (c, 0, p, NULL((void*)0), NULL((void*)0));
810
811 done:
812 if (p != NULL((void*)0))
813 ca_proplist_destroy (p);
814
815}
816
817static void
818finish_prepare_screenshot (char *initial_uri, GdkWindow *window, GdkRectangle *rectangle)
819{
820 ScreenshotDialog *dialog;
821 gboolean include_mask = (!take_window_shot && !take_area_shot);
822
823 /* always disable window border for full-desktop or selected-area screenshots */
824 if (!take_window_shot)
825 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, FALSE(0), include_mask);
826 else
827 {
828 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, include_border, include_mask);
829
830 switch (border_effect[0])
831 {
832 case 's': /* shadow */
833 screenshot_add_shadow (&screenshot);
834 break;
835 case 'b': /* border */
836 screenshot_add_border (&screenshot);
837 break;
838 case 'n': /* none */
839 default:
840 break;
841 }
842 }
843
844 /* release now the lock, it was acquired when we were finding the window */
845 screenshot_release_lock ();
846
847 if (screenshot == NULL((void*)0))
848 {
849 screenshot_show_error_dialog (NULL((void*)0),
850 _("Unable to take a screenshot of the current window")gettext ("Unable to take a screenshot of the current window"),
851 NULL((void*)0));
852 exit (1);
853 }
854
855 play_sound_effect (window);
856
857 if (noninteractive_clipboard_arg) {
858 save_screenshot_in_clipboard (gdk_window_get_display (window), screenshot);
859 g_free (initial_uri);
860 /* Done here: */
861 gtk_main_quit ();
862 return;
863 }
864
865 dialog = screenshot_dialog_new (screenshot, initial_uri, take_window_shot);
866 g_free (initial_uri);
867
868 screenshot_save_start (screenshot, save_done_notification, dialog);
869
870 run_dialog (dialog);
871}
872
873static void
874async_existence_job_free (AsyncExistenceJob *job)
875{
876 if (!job)
877 return;
878
879 g_free (job->base_uris[1]);
880 g_free (job->base_uris[2]);
881
882 if (job->rectangle != NULL((void*)0))
883 g_slice_free (GdkRectangle, job->rectangle)do { if (1) g_slice_free1 (sizeof (GdkRectangle), (job->rectangle
)); else (void) ((GdkRectangle*) 0 == (job->rectangle)); }
while (0)
;
884
885 g_slice_free (AsyncExistenceJob, job)do { if (1) g_slice_free1 (sizeof (AsyncExistenceJob), (job))
; else (void) ((AsyncExistenceJob*) 0 == (job)); } while (0)
;
886}
887
888static gboolean
889check_file_done (gpointer user_data)
890{
891 AsyncExistenceJob *job = user_data;
892
893 finish_prepare_screenshot (job->retval, job->window, job->rectangle);
894
895 async_existence_job_free (job);
896
897 return FALSE(0);
898}
899
900static char *
901build_uri (AsyncExistenceJob *job)
902{
903 char *retval, *file_name;
904 char *timestamp;
905 GDateTime *d;
906
907 d = g_date_time_new_now_local ();
908 timestamp = g_date_time_format (d, "%Y-%m-%d %H-%M-%S");
909 g_date_time_unref (d);
910
911 if (job->iteration == 0)
912 {
913 /* translators: this is the name of the file that gets made up
914 * with the screenshot if the entire screen is taken */
915 file_name = g_strdup_printf (_("Screenshot at %s.png")gettext ("Screenshot at %s.png"), timestamp);
916 }
917 else
918 {
919 /* translators: this is the name of the file that gets
920 * made up with the screenshot if the entire screen is
921 * taken */
922 file_name = g_strdup_printf (_("Screenshot at %s - %d.png")gettext ("Screenshot at %s - %d.png"), timestamp, job->iteration);
923 }
924
925 retval = g_build_filename (job->base_uris[job->type], file_name, NULL((void*)0));
926 g_free (file_name);
927 g_free (timestamp);
928
929 return retval;
930}
931
932static gboolean
933try_check_file (GIOSchedulerJob *io_job,
934 GCancellable *cancellable,
935 gpointer data)
936{
937 AsyncExistenceJob *job = data;
938 GFile *file;
939 GFileInfo *info;
940 GError *error;
941 char *uri;
942
943retry:
944 error = NULL((void*)0);
945 uri = build_uri (job);
946 file = g_file_new_for_uri (uri);
947
948 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
949 G_FILE_QUERY_INFO_NONE, cancellable, &error);
950 if (info != NULL((void*)0))
951 {
952 /* file already exists, iterate again */
953 g_object_unref (info);
954 g_object_unref (file);
955 g_free (uri);
956
957 (job->iteration)++;
958
959 goto retry;
960 }
961 else
962 {
963 /* see the error to check whether the location is not accessible
964 * or the file does not exist.
965 */
966 if (error->code == G_IO_ERROR_NOT_FOUND)
967 {
968 GFile *parent;
969
970 /* if the parent directory doesn't exist as well, forget the saved
971 * directory and treat this as a generic error.
972 */
973
974 parent = g_file_get_parent (file);
975
976 if (!g_file_query_exists (parent, NULL((void*)0)))
977 {
978 (job->type)++;
979 job->iteration = 0;
980
981 g_object_unref (file);
982 g_object_unref (parent);
983 goto retry;
984 }
985 else
986 {
987 job->retval = uri;
988
989 g_object_unref (parent);
990 goto out;
991 }
992 }
993 else
994 {
995 /* another kind of error, assume this location is not
996 * accessible.
997 */
998 g_free (uri);
999 if (job->type == TEST_TMP)
1000 {
1001 job->retval = NULL((void*)0);
1002 goto out;
1003 }
1004 else
1005 {
1006 (job->type)++;
1007 job->iteration = 0;
1008
1009 g_error_free (error);
1010 g_object_unref (file);
1011 goto retry;
1012 }
1013 }
1014 }
1015
1016out:
1017 g_error_free (error);
1018 g_object_unref (file);
1019
1020 g_io_scheduler_job_send_to_mainloop_async (io_job,
1021 check_file_done,
1022 job,
1023 NULL((void*)0));
1024 return FALSE(0);
1025}
1026
1027static GdkWindow *
1028find_current_window (void)
1029{
1030 GdkWindow *window;
1031
1032 if (!screenshot_grab_lock ())
1033 exit (0);
1034
1035 if (take_window_shot)
1036 {
1037 window = screenshot_find_current_window ();
1038 if (!window)
1039 {
1040 take_window_shot = FALSE(0);
1041 window = gdk_get_default_root_window ();
1042 }
1043 }
1044 else
1045 {
1046 window = gdk_get_default_root_window ();
1047 }
1048
1049 return window;
1050}
1051
1052static void
1053push_check_file_job (GdkRectangle *rectangle)
1054{
1055 AsyncExistenceJob *job;
1056
1057 job = g_slice_new0 (AsyncExistenceJob)((AsyncExistenceJob*) g_slice_alloc0 (sizeof (AsyncExistenceJob
)))
;
1058 job->base_uris[0] = last_save_dir;
1059 /* we'll have to free these two */
1060 job->base_uris[1] = get_desktop_dir ();
1061 job->base_uris[2] = g_strconcat ("file://", g_get_tmp_dir (), NULL((void*)0));
1062 job->iteration = 0;
1063 job->type = TEST_LAST_DIR;
1064 job->window = find_current_window ();
1065
1066 if (rectangle != NULL((void*)0))
1067 {
1068 job->rectangle = g_slice_new0 (GdkRectangle)((GdkRectangle*) g_slice_alloc0 (sizeof (GdkRectangle)));
1069 job->rectangle->x = rectangle->x;
1070 job->rectangle->y = rectangle->y;
1071 job->rectangle->width = rectangle->width;
1072 job->rectangle->height = rectangle->height;
1073 }
1074
1075 /* Check if the area selection was cancelled */
1076 if (job->rectangle &&
1077 (job->rectangle->width == 0 || job->rectangle->height == 0))
1078 {
1079 async_existence_job_free (job);
1080 gtk_main_quit ();
1081 return;
1082 }
1083
1084 g_io_scheduler_push_job (try_check_file,
1085 job,
1086 NULL((void*)0),
1087 0, NULL((void*)0));
1088
1089}
1090
1091static void
1092rectangle_found_cb (GdkRectangle *rectangle)
1093{
1094 push_check_file_job (rectangle);
1095}
1096
1097static void
1098prepare_screenshot (void)
1099{
1100 if (take_area_shot)
1101 screenshot_select_area_async (rectangle_found_cb);
1102 else
1103 push_check_file_job (NULL((void*)0));
1104}
1105
1106static gboolean
1107prepare_screenshot_timeout (gpointer data)
1108{
1109 prepare_screenshot ();
1110 save_options ();
1111
1112 return FALSE(0);
1113}
1114
1115static gchar *
1116get_desktop_dir (void)
1117{
1118 gboolean desktop_is_home_dir = FALSE(0);
1119 gchar *desktop_dir;
1120
1121 /* Check if caja schema is installed before trying to read settings */
1122 GSettingsSchema *schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1123 CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences",
1124 FALSE(0));
1125
1126 if (schema != NULL((void*)0)) {
1127 GSettings *caja_prefs;
1128
1129 caja_prefs = g_settings_new (CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences");
1130 desktop_is_home_dir = g_settings_get_boolean (caja_prefs, "desktop-is-home-dir");
1131
1132 g_object_unref (caja_prefs);
1133 g_settings_schema_unref (schema);
1134 }
1135
1136 if (desktop_is_home_dir)
1137 desktop_dir = g_strconcat ("file://", g_get_home_dir (), NULL((void*)0));
1138 else
1139 desktop_dir = g_strconcat ("file://", g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), NULL((void*)0));
1140
1141 return desktop_dir;
1142}
1143
1144/* Taken from mate-vfs-utils.c */
1145static char *
1146expand_initial_tilde (const char *path)
1147{
1148 char *slash_after_user_name, *user_name;
1149 struct passwd *passwd_file_entry;
1150
1151 if (path[1] == '/' || path[1] == '\0') {
1152 return g_strconcat (g_get_home_dir (), &path[1], NULL((void*)0));
1153 }
1154
1155 slash_after_user_name = strchr (&path[1], '/');
1156 if (slash_after_user_name == NULL((void*)0)) {
1157 user_name = g_strdup (&path[1])g_strdup_inline (&path[1]);
1158 } else {
1159 user_name = g_strndup (&path[1],
1160 slash_after_user_name - &path[1]);
1161 }
1162 passwd_file_entry = getpwnam (user_name);
1163 g_free (user_name);
1164
1165 if (passwd_file_entry == NULL((void*)0) || passwd_file_entry->pw_dir == NULL((void*)0)) {
1166 return g_strdup (path)g_strdup_inline (path);
1167 }
1168
1169 return g_strconcat (passwd_file_entry->pw_dir,
1170 slash_after_user_name,
1171 NULL((void*)0));
1172}
1173
1174/* Load options */
1175static void
1176load_options (void)
1177{
1178 /* Find various dirs */
1179 last_save_dir = g_settings_get_string (settings,
1180 LAST_SAVE_DIRECTORY_KEY"last-save-directory");
1181
1182 if (*last_save_dir == '\0')
1183 {
1184 g_free (last_save_dir);
1185 last_save_dir = get_desktop_dir ();
1186 }
1187 else if (last_save_dir[0] == '~')
1188 {
1189 char *tmp = expand_initial_tilde (last_save_dir);
1190 g_free (last_save_dir);
1191 last_save_dir = tmp;
1192 }
1193
1194 include_border = g_settings_get_boolean (settings,
1195 INCLUDE_BORDER_KEY"include-border");
1196
1197 include_pointer = g_settings_get_boolean (settings,
1198 INCLUDE_POINTER_KEY"include-pointer");
1199
1200 border_effect = g_settings_get_string (settings,
1201 BORDER_EFFECT_KEY"border-effect");
1202 if (!border_effect)
1203 border_effect = g_strdup ("none")g_strdup_inline ("none");
1204
1205 delay = g_settings_get_int (settings, DELAY_KEY"delay");
1206}
1207
1208static void
1209save_options (void)
1210{
1211 g_settings_set_boolean (settings,
1212 INCLUDE_BORDER_KEY"include-border", include_border);
1213 g_settings_set_boolean (settings,
1214 INCLUDE_POINTER_KEY"include-pointer", include_pointer);
1215 g_settings_set_int (settings, DELAY_KEY"delay", delay);
1216 g_settings_set_string (settings,
1217 BORDER_EFFECT_KEY"border-effect", border_effect);
1218}
1219
1220void
1221loop_dialog_screenshot (void)
1222{
1223 /* interactive mode overrides everything */
1224 if (interactive_arg)
1225 {
1226 GtkWidget *dialog;
1227 gint response;
1228
1229 dialog = create_interactive_dialog ();
1230 response = gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
1231 gtk_widget_destroy (dialog);
1232
1233 switch (response)
1234 {
1235 case GTK_RESPONSE_DELETE_EVENT:
1236 case GTK_RESPONSE_CANCEL:
1237 return;
1238 case GTK_RESPONSE_OK:
1239 break;
1240 default:
1241 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "mate-screenshot.c"
, 1241, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1242 break;
1243 }
1244 }
1245
1246 if (((delay > 0 && interactive_arg) || delay_arg > 0) &&
1247 !take_area_shot)
1248 {
1249 g_timeout_add (delay * 1000,
1250 prepare_screenshot_timeout,
1251 NULL((void*)0));
1252 }
1253 else
1254 {
1255 if (interactive_arg)
1256 {
1257 /* HACK: give time to the dialog to actually disappear.
1258 * We don't have any way to tell when the compositor has finished
1259 * re-drawing.
1260 */
1261 g_timeout_add (200,
1262 prepare_screenshot_timeout, NULL((void*)0));
1263 }
1264 else
1265 g_idle_add (prepare_screenshot_timeout, NULL((void*)0));
1266 }
1267
1268 gtk_main ();
1269}
1270
1271/* main */
1272int
1273main (int argc, char *argv[])
1274{
1275 GOptionContext *context;
1276 gboolean window_arg = FALSE(0);
1277 gboolean area_arg = FALSE(0);
1278 gboolean include_border_arg = FALSE(0);
1279 gboolean disable_border_arg = FALSE(0);
1280 gchar *border_effect_arg = NULL((void*)0);
1281 gboolean version_arg = FALSE(0);
1282 GError *error = NULL((void*)0);
1283
1284 const GOptionEntry entries[] = {
1285 { "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen")("Grab a window instead of the entire screen"), NULL((void*)0) },
1286 { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen")("Grab an area of the screen instead of the entire screen"), NULL((void*)0) },
1287 { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &noninteractive_clipboard_arg, N_("Send grabbed area directly to the clipboard")("Send grabbed area directly to the clipboard"), NULL((void*)0) },
1288 { "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot")("Include the window border with the screenshot"), NULL((void*)0) },
1289 { "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot")("Remove the window border from the screenshot"), NULL((void*)0) },
1290 { "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]")("Take screenshot after specified delay [in seconds]"), N_("seconds")("seconds") },
1291 { "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)")("Effect to add to the border (shadow, border or none)"), N_("effect")("effect") },
1292 { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options")("Interactively set options"), NULL((void*)0) },
1293 { "version", 0, 0, G_OPTION_ARG_NONE, &version_arg, N_("Print version information and exit")("Print version information and exit"), NULL((void*)0) },
1294 { NULL((void*)0), 0, 0, G_OPTION_ARG_NONE, NULL((void*)0), NULL((void*)0), NULL((void*)0) },
1295 };
1296
1297#ifdef ENABLE_NLS1
1298 setlocale (LC_ALL6, "");
1299 bindtextdomain (GETTEXT_PACKAGE"mate-utils", MATELOCALEDIR"/usr/local/share/locale");
1300 bind_textdomain_codeset (GETTEXT_PACKAGE"mate-utils", "UTF-8");
1301 textdomain (GETTEXT_PACKAGE"mate-utils");
1302#endif /* ENABLE_NLS */
1303
1304 context = g_option_context_new (_("Take a picture of the screen")gettext ("Take a picture of the screen"));
1305 g_option_context_set_ignore_unknown_options (context, FALSE(0));
1306 g_option_context_set_help_enabled (context, TRUE(!(0)));
1307 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE"mate-utils");
1308 g_option_context_add_group (context, gtk_get_option_group (TRUE(!(0))));
1309
1310 g_option_context_parse (context, &argc, &argv, &error);
1311
1312 if (error) {
1313 g_critical ("Unable to parse arguments: %s", error->message);
1314 g_error_free (error);
1315 g_option_context_free (context);
1316 exit (1);
1317 }
1318
1319 g_option_context_free (context);
1320
1321 if (version_arg) {
1322 g_print ("%s %s\n", g_get_application_name (), VERSION"1.27.0");
1323 exit (EXIT_SUCCESS0);
1324 }
1325
1326 if (interactive_arg && noninteractive_clipboard_arg) {
1327 g_printerr (_("Conflicting options: --clipboard and --interactive should not be "gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
1328 "used at the same time.\n")gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
);
1329 exit (1);
1330 }
1331
1332 if (window_arg && area_arg) {
1333 g_printerr (_("Conflicting options: --window and --area should not be "gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
1334 "used at the same time.\n")gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
);
1335 exit (1);
1336 }
1337
1338 gtk_window_set_default_icon_name (SCREENSHOOTER_ICON"applets-screenshooter");
1339
1340 settings = g_settings_new (MATE_SCREENSHOT_SCHEMA"org.mate.screenshot");
1341 load_options ();
1342 /* allow the command line to override options */
1343 if (window_arg)
1344 take_window_shot = TRUE(!(0));
1345
1346 if (area_arg)
1347 take_area_shot = TRUE(!(0));
1348
1349 if (include_border_arg)
1350 include_border = TRUE(!(0));
1351
1352 if (disable_border_arg)
1353 include_border = FALSE(0);
1354
1355 if (border_effect_arg)
1356 {
1357 g_free (border_effect);
1358 border_effect = border_effect_arg;
1359 }
1360
1361 if (delay_arg > 0)
1362 delay = delay_arg;
This statement is never executed
1363
1364 loop_dialog_screenshot();
1365
1366 return EXIT_SUCCESS0;
1367}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ace5d0.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ace5d0.html new file mode 100644 index 00000000..2b08d1cf --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ace5d0.html @@ -0,0 +1,2833 @@ + + + +gdict-client-context.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-client-context.c
Warning:line 1379, column 13
Value stored to 'p' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-client-context.c
Warning:line 1481, column 40
Null pointer passed to 1st parameter expecting 'nonnull'
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:gsearchtool/mate-submodules/libegg/eggsmclient-xsmp.c
Warning:line 1199, column 18
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name eggsmclient-xsmp.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/gsearchtool/mate-submodules/libegg -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D EGG_SM_CLIENT_BACKEND_XSMP -D G_LOG_DOMAIN="EggSMClient" -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D PIC -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/gsearchtool/mate-submodules/libegg -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c eggsmclient-xsmp.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/*
2 * Copyright (C) 2007 Novell, Inc.
3 *
4 * Inspired by various other pieces of code including GsmClient (C)
5 * 2001 Havoc Pennington, MateClient (C) 1998 Carsten Schaar, and twm
6 * session code (C) 1998 The Open Group.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25
26#include "eggsmclient.h"
27#include "eggsmclient-private.h"
28
29#include "eggdesktopfile.h"
30
31#include <errno(*__errno_location ()).h>
32#include <fcntl.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <X11/SM/SMlib.h>
37
38#include <gtk/gtk.h>
39#include <gdk/gdk.h>
40
41#if defined(GDK_WINDOWING_X11) || defined(HAVE_X11)
42#include <gdk/gdkx.h>
43#endif
44
45#define EGG_TYPE_SM_CLIENT_XSMP(egg_sm_client_xsmp_get_type ()) (egg_sm_client_xsmp_get_type ())
46#define EGG_SM_CLIENT_XSMP(obj)((((EggSMClientXSMP*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((egg_sm_client_xsmp_get_type ()))))))
(G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP)(((EggSMClientXSMP*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((egg_sm_client_xsmp_get_type ())))))
)
47#define EGG_SM_CLIENT_XSMP_CLASS(klass)((((EggSMClientXSMPClass*) (void *) g_type_check_class_cast (
(GTypeClass*) ((klass)), ((egg_sm_client_xsmp_get_type ()))))
))
(G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)(((EggSMClientXSMPClass*) (void *) g_type_check_class_cast ((
GTypeClass*) ((klass)), ((egg_sm_client_xsmp_get_type ())))))
)
48#define EGG_IS_SM_CLIENT_XSMP(obj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
49#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; }))))
(G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; })))
)
50#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj)((((EggSMClientXSMPClass*) (((GTypeInstance*) ((obj)))->g_class
))))
(G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)(((EggSMClientXSMPClass*) (((GTypeInstance*) ((obj)))->g_class
)))
)
51
52typedef struct _EggSMClientXSMP EggSMClientXSMP;
53typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass;
54
55/* These mostly correspond to the similarly-named states in section
56 * 9.1 of the XSMP spec. Some of the states there aren't represented
57 * here, because we don't need them. SHUTDOWN_CANCELLED is slightly
58 * different from the spec; we use it when the client is IDLE after a
59 * ShutdownCancelled message, but the application is still interacting
60 * and doesn't know the shutdown has been cancelled yet.
61 */
62typedef enum
63{
64 XSMP_STATE_IDLE,
65 XSMP_STATE_SAVE_YOURSELF,
66 XSMP_STATE_INTERACT_REQUEST,
67 XSMP_STATE_INTERACT,
68 XSMP_STATE_SAVE_YOURSELF_DONE,
69 XSMP_STATE_SHUTDOWN_CANCELLED,
70 XSMP_STATE_CONNECTION_CLOSED
71} EggSMClientXSMPState;
72
73static const char *state_names[] =
74{
75 "idle",
76 "save-yourself",
77 "interact-request",
78 "interact",
79 "save-yourself-done",
80 "shutdown-cancelled",
81 "connection-closed"
82};
83
84#define EGG_SM_CLIENT_XSMP_STATE(xsmp)(state_names[(xsmp)->state]) (state_names[(xsmp)->state])
85
86struct _EggSMClientXSMP
87{
88 EggSMClient parent;
89
90 SmcConn connection;
91 char *client_id;
92
93 EggSMClientXSMPState state;
94 char **restart_command;
95 gboolean set_restart_command;
96 int restart_style;
97 char **discard_command;
98 gboolean set_discard_command;
99
100 guint idle;
101
102 /* Current SaveYourself state */
103 guint expecting_initial_save_yourself : 1;
104 guint need_save_state : 1;
105 guint need_quit_requested : 1;
106 guint interact_errors : 1;
107 guint shutting_down : 1;
108
109 /* Todo list */
110 guint waiting_to_set_initial_properties : 1;
111 guint waiting_to_emit_quit : 1;
112 guint waiting_to_emit_quit_cancelled : 1;
113 guint waiting_to_save_myself : 1;
114
115};
116
117struct _EggSMClientXSMPClass
118{
119 EggSMClientClass parent_class;
120
121};
122
123static void sm_client_xsmp_startup (EggSMClient *client,
124 const char *client_id);
125static void sm_client_xsmp_set_restart_command (EggSMClient *client,
126 int argc,
127 const char **argv);
128static void sm_client_xsmp_set_discard_command (EggSMClient *client,
129 int argc,
130 const char **argv);
131static void sm_client_xsmp_will_quit (EggSMClient *client,
132 gboolean will_quit);
133static gboolean sm_client_xsmp_end_session (EggSMClient *client,
134 EggSMClientEndStyle style,
135 gboolean request_confirmation);
136
137static void xsmp_save_yourself (SmcConn smc_conn,
138 SmPointer client_data,
139 int save_style,
140 Boolint shutdown,
141 int interact_style,
142 Boolint fast);
143static void xsmp_die (SmcConn smc_conn,
144 SmPointer client_data);
145static void xsmp_save_complete (SmcConn smc_conn,
146 SmPointer client_data);
147static void xsmp_shutdown_cancelled (SmcConn smc_conn,
148 SmPointer client_data);
149static void xsmp_interact (SmcConn smc_conn,
150 SmPointer client_data);
151
152static SmProp *array_prop (const char *name,
153 ...);
154static SmProp *ptrarray_prop (const char *name,
155 GPtrArray *values);
156static SmProp *string_prop (const char *name,
157 const char *value);
158static SmProp *card8_prop (const char *name,
159 unsigned char value);
160
161static void set_properties (EggSMClientXSMP *xsmp, ...);
162static void delete_properties (EggSMClientXSMP *xsmp, ...);
163
164static GPtrArray *generate_command (char **restart_command,
165 const char *client_id,
166 const char *state_file);
167
168static void save_state (EggSMClientXSMP *xsmp);
169static void do_save_yourself (EggSMClientXSMP *xsmp);
170static void update_pending_events (EggSMClientXSMP *xsmp);
171
172static void ice_init (void);
173static gboolean process_ice_messages (IceConn ice_conn);
174static void smc_error_handler (SmcConn smc_conn,
175 Boolint swap,
176 int offending_minor_opcode,
177 unsigned long offending_sequence,
178 int error_class,
179 int severity,
180 SmPointer values);
181
182G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT)static void egg_sm_client_xsmp_init (EggSMClientXSMP *self); static
void egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass
); static GType egg_sm_client_xsmp_get_type_once (void); static
gpointer egg_sm_client_xsmp_parent_class = ((void*)0); static
gint EggSMClientXSMP_private_offset; static void egg_sm_client_xsmp_class_intern_init
(gpointer klass) { egg_sm_client_xsmp_parent_class = g_type_class_peek_parent
(klass); if (EggSMClientXSMP_private_offset != 0) g_type_class_adjust_private_offset
(klass, &EggSMClientXSMP_private_offset); egg_sm_client_xsmp_class_init
((EggSMClientXSMPClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer egg_sm_client_xsmp_get_instance_private
(EggSMClientXSMP *self) { return (((gpointer) ((guint8*) (self
) + (glong) (EggSMClientXSMP_private_offset)))); } GType egg_sm_client_xsmp_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 = egg_sm_client_xsmp_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 egg_sm_client_xsmp_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((egg_sm_client_get_type ()), g_intern_static_string ("EggSMClientXSMP"
), sizeof (EggSMClientXSMPClass), (GClassInitFunc)(void (*)(void
)) egg_sm_client_xsmp_class_intern_init, sizeof (EggSMClientXSMP
), (GInstanceInitFunc)(void (*)(void)) egg_sm_client_xsmp_init
, (GTypeFlags) 0); { {{};} } return g_define_type_id; }
183
184static void
185egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp)
186{
187 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
188 xsmp->connection = NULL((void*)0);
189 xsmp->restart_style = SmRestartIfRunning0;
190}
191
192static void
193egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
194{
195 EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
196
197 sm_client_class->startup = sm_client_xsmp_startup;
198 sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command;
199 sm_client_class->set_discard_command = sm_client_xsmp_set_discard_command;
200 sm_client_class->will_quit = sm_client_xsmp_will_quit;
201 sm_client_class->end_session = sm_client_xsmp_end_session;
202}
203
204EggSMClient *
205egg_sm_client_xsmp_new (void)
206{
207 if (!g_getenv ("SESSION_MANAGER"))
208 return NULL((void*)0);
209
210 return g_object_new (EGG_TYPE_SM_CLIENT_XSMP(egg_sm_client_xsmp_get_type ()), NULL((void*)0));
211}
212
213static gboolean
214sm_client_xsmp_set_initial_properties (gpointer user_data)
215{
216 EggSMClientXSMP *xsmp = user_data;
217 EggDesktopFile *desktop_file;
218 GPtrArray *clone, *restart;
219 char pid_str[64];
220
221 if (xsmp->idle)
222 {
223 g_source_remove (xsmp->idle);
224 xsmp->idle = 0;
225 }
226 xsmp->waiting_to_set_initial_properties = FALSE(0);
227
228 if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART)
229 xsmp->restart_style = SmRestartNever3;
230
231 /* Parse info out of desktop file */
232 desktop_file = egg_get_desktop_file ();
233 if (desktop_file)
234 {
235 GError *err = NULL((void*)0);
236 char **argv;
237 int argc;
238
239 if (xsmp->restart_style == SmRestartIfRunning0)
240 {
241 if (egg_desktop_file_get_boolean (desktop_file,
242 "X-MATE-AutoRestart", NULL((void*)0)))
243 xsmp->restart_style = SmRestartImmediately2;
244 }
245
246 if (!xsmp->set_restart_command)
247 {
248 char *cmdline;
249
250 cmdline = egg_desktop_file_parse_exec (desktop_file, NULL((void*)0), &err);
251 if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err))
252 {
253 egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp),
254 argc, (const char **)argv);
255 g_strfreev (argv);
256 }
257 else
258 {
259 g_warning ("Could not parse Exec line in desktop file: %s",
260 err->message);
261 g_error_free (err);
262 }
263 g_free (cmdline);
264 }
265 }
266
267 if (!xsmp->set_restart_command)
268 xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1);
269
270 clone = generate_command (xsmp->restart_command, NULL((void*)0), NULL((void*)0));
271 restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL((void*)0));
272
273 g_debug ("Setting initial properties");
274
275 /* Program, CloneCommand, RestartCommand, and UserID are required.
276 * ProcessID isn't required, but the SM may be able to do something
277 * useful with it.
278 */
279 g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ());
280 set_properties (xsmp,
281 string_prop (SmProgram"Program", g_get_prgname ()),
282 ptrarray_prop (SmCloneCommand"CloneCommand", clone),
283 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
284 string_prop (SmUserID"UserID", g_get_user_name ()),
285 string_prop (SmProcessID"ProcessID", pid_str),
286 card8_prop (SmRestartStyleHint"RestartStyleHint", xsmp->restart_style),
287 NULL((void*)0));
288 g_ptr_array_free (clone, TRUE(!(0)));
289 g_ptr_array_free (restart, TRUE(!(0)));
290
291 if (desktop_file)
292 {
293 set_properties (xsmp,
294 string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)),
295 NULL((void*)0));
296 }
297
298 update_pending_events (xsmp);
299 return FALSE(0);
300}
301
302/* This gets called from two different places: xsmp_die() (when the
303 * server asks us to disconnect) and process_ice_messages() (when the
304 * server disconnects unexpectedly).
305 */
306static void
307sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp)
308{
309 SmcConn connection;
310
311 if (!xsmp->connection)
312 return;
313
314 g_debug ("Disconnecting");
315
316 connection = xsmp->connection;
317 xsmp->connection = NULL((void*)0);
318 SmcCloseConnection (connection, 0, NULL((void*)0));
319 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
320
321 xsmp->waiting_to_save_myself = FALSE(0);
322 update_pending_events (xsmp);
323}
324
325static void
326sm_client_xsmp_startup (EggSMClient *client,
327 const char *client_id)
328{
329 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
330 SmcCallbacks callbacks;
331 char *ret_client_id;
332 char error_string_ret[256];
333
334 xsmp->client_id = g_strdup (client_id)g_strdup_inline (client_id);
335
336 ice_init ();
337 SmcSetErrorHandler (smc_error_handler);
338
339 callbacks.save_yourself.callback = xsmp_save_yourself;
340 callbacks.die.callback = xsmp_die;
341 callbacks.save_complete.callback = xsmp_save_complete;
342 callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
343
344 callbacks.save_yourself.client_data = xsmp;
345 callbacks.die.client_data = xsmp;
346 callbacks.save_complete.client_data = xsmp;
347 callbacks.shutdown_cancelled.client_data = xsmp;
348
349 client_id = NULL((void*)0);
350 error_string_ret[0] = '\0';
351 xsmp->connection =
352 SmcOpenConnection (NULL((void*)0), xsmp, SmProtoMajor1, SmProtoMinor0,
353 SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) |
354 SmcSaveCompleteProcMask(1L << 2) |
355 SmcShutdownCancelledProcMask(1L << 3),
356 &callbacks,
357 xsmp->client_id, &ret_client_id,
358 sizeof (error_string_ret), error_string_ret);
359
360 if (!xsmp->connection)
361 {
362 g_warning ("Failed to connect to the session manager: %s\n",
363 error_string_ret[0] ?
364 error_string_ret : "no error message given");
365 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
366 return;
367 }
368
369 /* We expect a pointless initial SaveYourself if either (a) we
370 * didn't have an initial client ID, or (b) we DID have an initial
371 * client ID, but the server rejected it and gave us a new one.
372 */
373 if (!xsmp->client_id ||
374 (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0))
375 xsmp->expecting_initial_save_yourself = TRUE(!(0));
376
377 if (ret_client_id)
378 {
379 g_free (xsmp->client_id);
380 xsmp->client_id = g_strdup (ret_client_id)g_strdup_inline (ret_client_id);
381 free (ret_client_id);
382
383#if defined(GDK_WINDOWING_X11) || defined(HAVE_X11)
384 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(gdk_display_get_default ())); GType __t = ((gdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
385 gdk_x11_set_sm_client_id (xsmp->client_id);
386#endif
387
388 g_debug ("Got client ID \"%s\"", xsmp->client_id);
389 }
390
391 xsmp->state = XSMP_STATE_IDLE;
392
393 /* Do not set the initial properties until we reach the main loop,
394 * so that the application has a chance to call
395 * egg_set_desktop_file(). (This may also help the session manager
396 * have a better idea of when the application is fully up and
397 * running.)
398 */
399 xsmp->waiting_to_set_initial_properties = TRUE(!(0));
400 xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client);
401}
402
403static void
404sm_client_xsmp_set_restart_command (EggSMClient *client,
405 int argc,
406 const char **argv)
407{
408 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
409 int i;
410
411 g_strfreev (xsmp->restart_command);
412
413 xsmp->restart_command = g_new (char *, argc + 1)((char * *) g_malloc_n ((argc + 1), sizeof (char *)));
414 for (i = 0; i < argc; i++)
415 xsmp->restart_command[i] = g_strdup (argv[i])g_strdup_inline (argv[i]);
416 xsmp->restart_command[i] = NULL((void*)0);
417
418 xsmp->set_restart_command = TRUE(!(0));
419}
420
421static void
422sm_client_xsmp_set_discard_command (EggSMClient *client,
423 int argc,
424 const char **argv)
425{
426 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
427 int i;
428
429 g_strfreev (xsmp->discard_command);
430
431 xsmp->discard_command = g_new (char *, argc + 1)((char * *) g_malloc_n ((argc + 1), sizeof (char *)));
432 for (i = 0; i < argc; i++)
433 xsmp->discard_command[i] = g_strdup (argv[i])g_strdup_inline (argv[i]);
434 xsmp->discard_command[i] = NULL((void*)0);
435
436 xsmp->set_discard_command = TRUE(!(0));
437}
438
439static void
440sm_client_xsmp_will_quit (EggSMClient *client,
441 gboolean will_quit)
442{
443 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
444
445 if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED)
446 {
447 /* The session manager has already exited! Schedule a quit
448 * signal.
449 */
450 xsmp->waiting_to_emit_quit = TRUE(!(0));
451 update_pending_events (xsmp);
452 return;
453 }
454 else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
455 {
456 /* We received a ShutdownCancelled message while the application
457 * was interacting; Schedule a quit_cancelled signal.
458 */
459 xsmp->waiting_to_emit_quit_cancelled = TRUE(!(0));
460 update_pending_events (xsmp);
461 return;
462 }
463
464 g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT)do { if ((xsmp->state == XSMP_STATE_INTERACT)) { } else { g_return_if_fail_warning
("EggSMClient", ((const char*) (__func__)), "xsmp->state == XSMP_STATE_INTERACT"
); return; } } while (0)
;
465
466 g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True");
467 SmcInteractDone (xsmp->connection, !will_quit);
468
469 if (will_quit && xsmp->need_save_state)
470 save_state (xsmp);
471
472 g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False");
473 SmcSaveYourselfDone (xsmp->connection, will_quit);
474 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
475}
476
477static gboolean
478sm_client_xsmp_end_session (EggSMClient *client,
479 EggSMClientEndStyle style,
480 gboolean request_confirmation)
481{
482 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
483 int save_type;
484
485 /* To end the session via XSMP, we have to send a
486 * SaveYourselfRequest. We aren't allowed to do that if anything
487 * else is going on, but we don't want to expose this fact to the
488 * application. So we do our best to patch things up here...
489 *
490 * In the worst case, this method might block for some length of
491 * time in process_ice_messages, but the only time that code path is
492 * honestly likely to get hit is if the application tries to end the
493 * session as the very first thing it does, in which case it
494 * probably won't actually block anyway. It's not worth gunking up
495 * the API to try to deal nicely with the other 0.01% of cases where
496 * this happens.
497 */
498
499 while (xsmp->state != XSMP_STATE_IDLE ||
500 xsmp->expecting_initial_save_yourself)
501 {
502 /* If we're already shutting down, we don't need to do anything. */
503 if (xsmp->shutting_down)
504 return TRUE(!(0));
505
506 switch (xsmp->state)
507 {
508 case XSMP_STATE_CONNECTION_CLOSED:
509 return FALSE(0);
510
511 case XSMP_STATE_SAVE_YOURSELF:
512 /* Trying to log out from the save_state callback? Whatever.
513 * Abort the save_state.
514 */
515 SmcSaveYourselfDone (xsmp->connection, FALSE(0));
516 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
517 break;
518
519 case XSMP_STATE_INTERACT_REQUEST:
520 case XSMP_STATE_INTERACT:
521 case XSMP_STATE_SHUTDOWN_CANCELLED:
522 /* Already in a shutdown-related state, just ignore
523 * the new shutdown request...
524 */
525 return TRUE(!(0));
526
527 case XSMP_STATE_IDLE:
528 if (xsmp->waiting_to_set_initial_properties)
529 sm_client_xsmp_set_initial_properties (xsmp);
530
531 if (!xsmp->expecting_initial_save_yourself)
532 break;
533 /* else fall through */
534
535 case XSMP_STATE_SAVE_YOURSELF_DONE:
536 /* We need to wait for some response from the server.*/
537 process_ice_messages (SmcGetIceConnection (xsmp->connection));
538 break;
539
540 default:
541 /* Hm... shouldn't happen */
542 return FALSE(0);
543 }
544 }
545
546 /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and
547 * the user chooses to save the session. But mate-session will do
548 * the wrong thing if we pass SmSaveBoth and the user chooses NOT to
549 * save the session... Sigh.
550 */
551 if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session"))
552 save_type = SmSaveBoth2;
553 else
554 save_type = SmSaveGlobal0;
555
556 g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : "");
557 SmcRequestSaveYourself (xsmp->connection,
558 save_type,
559 True1, /* shutdown */
560 SmInteractStyleAny2,
561 !request_confirmation, /* fast */
562 True1 /* global */);
563 return TRUE(!(0));
564}
565
566static gboolean
567idle_do_pending_events (gpointer data)
568{
569 EggSMClientXSMP *xsmp = data;
570 EggSMClient *client = data;
571
572 xsmp->idle = 0;
573
574 if (xsmp->waiting_to_emit_quit)
575 {
576 xsmp->waiting_to_emit_quit = FALSE(0);
577 egg_sm_client_quit (client);
578 goto out;
579 }
580
581 if (xsmp->waiting_to_emit_quit_cancelled)
582 {
583 xsmp->waiting_to_emit_quit_cancelled = FALSE(0);
584 egg_sm_client_quit_cancelled (client);
585 xsmp->state = XSMP_STATE_IDLE;
586 }
587
588 if (xsmp->waiting_to_save_myself)
589 {
590 xsmp->waiting_to_save_myself = FALSE(0);
591 do_save_yourself (xsmp);
592 }
593
594out:
595 return FALSE(0);
596}
597
598static void
599update_pending_events (EggSMClientXSMP *xsmp)
600{
601 gboolean want_idle =
602 xsmp->waiting_to_emit_quit ||
603 xsmp->waiting_to_emit_quit_cancelled ||
604 xsmp->waiting_to_save_myself;
605
606 if (want_idle)
607 {
608 if (xsmp->idle == 0)
609 xsmp->idle = g_idle_add (idle_do_pending_events, xsmp);
610 }
611 else
612 {
613 if (xsmp->idle != 0)
614 g_source_remove (xsmp->idle);
615 xsmp->idle = 0;
616 }
617}
618
619static void
620fix_broken_state (EggSMClientXSMP *xsmp, const char *message,
621 gboolean send_interact_done,
622 gboolean send_save_yourself_done)
623{
624 g_warning ("Received XSMP %s message in state %s: client or server error",
625 message, EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
626
627 /* Forget any pending SaveYourself plans we had */
628 xsmp->waiting_to_save_myself = FALSE(0);
629 update_pending_events (xsmp);
630
631 if (send_interact_done)
632 SmcInteractDone (xsmp->connection, False0);
633 if (send_save_yourself_done)
634 SmcSaveYourselfDone (xsmp->connection, True1);
635
636 xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE;
637}
638
639/* SM callbacks */
640
641static void
642xsmp_save_yourself (SmcConn smc_conn,
643 SmPointer client_data,
644 int save_type,
645 Boolint shutdown,
646 int interact_style,
647 Boolint fast)
648{
649 EggSMClientXSMP *xsmp = client_data;
650 gboolean wants_quit_requested;
651
652 g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s",
653 save_type == SmSaveLocal1 ? "SmSaveLocal" :
654 save_type == SmSaveGlobal0 ? "SmSaveGlobal" : "SmSaveBoth",
655 shutdown ? "Shutdown" : "!Shutdown",
656 interact_style == SmInteractStyleAny2 ? "SmInteractStyleAny" :
657 interact_style == SmInteractStyleErrors1 ? "SmInteractStyleErrors" :
658 "SmInteractStyleNone", fast ? "Fast" : "!Fast",
659 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
660
661 if (xsmp->state != XSMP_STATE_IDLE &&
662 xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED)
663 {
664 fix_broken_state (xsmp, "SaveYourself", FALSE(0), TRUE(!(0)));
665 return;
666 }
667
668 if (xsmp->waiting_to_set_initial_properties)
669 sm_client_xsmp_set_initial_properties (xsmp);
670
671 /* If this is the initial SaveYourself, ignore it; we've already set
672 * properties and there's no reason to actually save state too.
673 */
674 if (xsmp->expecting_initial_save_yourself)
675 {
676 xsmp->expecting_initial_save_yourself = FALSE(0);
677
678 if (save_type == SmSaveLocal1 &&
679 interact_style == SmInteractStyleNone0 &&
680 !shutdown && !fast)
681 {
682 g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself");
683 SmcSaveYourselfDone (xsmp->connection, True1);
684 /* As explained in the comment at the end of
685 * do_save_yourself(), SAVE_YOURSELF_DONE is the correct
686 * state here, not IDLE.
687 */
688 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
689 return;
690 }
691 else
692 g_warning ("First SaveYourself was not the expected one!");
693 }
694
695 /* Even ignoring the "fast" flag completely, there are still 18
696 * different combinations of save_type, shutdown and interact_style.
697 * We interpret them as follows:
698 *
699 * Type Shutdown Interact Interpretation
700 * G F A/E/N do nothing (1)
701 * G T N do nothing (1)*
702 * G T A/E quit_requested (2)
703 * L/B F A/E/N save_state (3)
704 * L/B T N save_state (3)*
705 * L/B T A/E quit_requested, then save_state (4)
706 *
707 * 1. Do nothing, because the SM asked us to do something
708 * uninteresting (save open files, but then don't quit
709 * afterward) or rude (save open files without asking the user
710 * for confirmation).
711 *
712 * 2. Request interaction and then emit ::quit_requested. This
713 * perhaps isn't quite correct for the SmInteractStyleErrors
714 * case, but we don't care.
715 *
716 * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these
717 * rows essentially get demoted to SmSaveLocal, because their
718 * Global halves correspond to "do nothing".
719 *
720 * 4. Request interaction, emit ::quit_requested, and then emit
721 * ::save_state after interacting. This is the SmSaveBoth
722 * equivalent of #2, but we also promote SmSaveLocal shutdown
723 * SaveYourselfs to SmSaveBoth here, because we want to give
724 * the user a chance to save open files before quitting.
725 *
726 * (* It would be nice if we could do something useful when the
727 * session manager sends a SaveYourself with shutdown True and
728 * SmInteractStyleNone. But we can't, so we just pretend it didn't
729 * even tell us it was shutting down. The docs for ::quit mention
730 * that it might not always be preceded by ::quit_requested.)
731 */
732
733 /* As an optimization, we don't actually request interaction and
734 * emit ::quit_requested if the application isn't listening to the
735 * signal.
736 */
737 wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT(egg_sm_client_get_type ())), 0, FALSE(0));
738
739 xsmp->need_save_state = (save_type != SmSaveGlobal0);
740 xsmp->need_quit_requested = (shutdown && wants_quit_requested &&
741 interact_style != SmInteractStyleNone0);
742 xsmp->interact_errors = (interact_style == SmInteractStyleErrors1);
743
744 xsmp->shutting_down = shutdown;
745
746 do_save_yourself (xsmp);
747}
748
749static void
750do_save_yourself (EggSMClientXSMP *xsmp)
751{
752 if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
753 {
754 /* The SM cancelled a previous SaveYourself, but we haven't yet
755 * had a chance to tell the application, so we can't start
756 * processing this SaveYourself yet.
757 */
758 xsmp->waiting_to_save_myself = TRUE(!(0));
759 update_pending_events (xsmp);
760 return;
761 }
762
763 if (xsmp->need_quit_requested)
764 {
765 xsmp->state = XSMP_STATE_INTERACT_REQUEST;
766
767 g_debug ("Sending InteractRequest(%s)",
768 xsmp->interact_errors ? "Error" : "Normal");
769 SmcInteractRequest (xsmp->connection,
770 xsmp->interact_errors ? SmDialogError0 : SmDialogNormal1,
771 xsmp_interact,
772 xsmp);
773 return;
774 }
775
776 if (xsmp->need_save_state)
777 {
778 save_state (xsmp);
779
780 /* Though unlikely, the client could have been disconnected
781 * while the application was saving its state.
782 */
783 if (!xsmp->connection)
784 return;
785 }
786
787 g_debug ("Sending SaveYourselfDone(True)");
788 SmcSaveYourselfDone (xsmp->connection, True1);
789
790 /* The client state diagram in the XSMP spec says that after a
791 * non-shutdown SaveYourself, we go directly back to "idle". But
792 * everything else in both the XSMP spec and the libSM docs
793 * disagrees.
794 */
795 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
796}
797
798static void
799save_state (EggSMClientXSMP *xsmp)
800{
801 GKeyFile *state_file;
802 char *state_file_path, *data;
803 EggDesktopFile *desktop_file;
804 GPtrArray *restart, *discard;
805 int offset, fd;
806
807 /* We set xsmp->state before emitting save_state, but our caller is
808 * responsible for setting it back afterward.
809 */
810 xsmp->state = XSMP_STATE_SAVE_YOURSELF;
811
812 state_file = egg_sm_client_save_state ((EggSMClient *)xsmp);
813 if (!state_file)
814 {
815 restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL((void*)0));
816 set_properties (xsmp,
817 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
818 NULL((void*)0));
819 g_ptr_array_free (restart, TRUE(!(0)));
820
821 if (xsmp->set_discard_command)
822 {
823 discard = generate_command (xsmp->discard_command, NULL((void*)0), NULL((void*)0));
824 set_properties (xsmp,
825 ptrarray_prop (SmDiscardCommand"DiscardCommand", discard),
826 NULL((void*)0));
827 g_ptr_array_free (discard, TRUE(!(0)));
828 }
829 else
830 delete_properties (xsmp, SmDiscardCommand"DiscardCommand", NULL((void*)0));
831
832 return;
833 }
834
835 desktop_file = egg_get_desktop_file ();
836 if (desktop_file)
837 {
838 GKeyFile *merged_file;
839 char *desktop_file_path;
840
841 merged_file = g_key_file_new ();
842 desktop_file_path =
843 g_filename_from_uri (egg_desktop_file_get_source (desktop_file),
844 NULL((void*)0), NULL((void*)0));
845 if (desktop_file_path &&
846 g_key_file_load_from_file (merged_file, desktop_file_path,
847 G_KEY_FILE_KEEP_COMMENTS |
848 G_KEY_FILE_KEEP_TRANSLATIONS, NULL((void*)0)))
849 {
850 guint g, k, i;
851 char **groups, **keys, *value, *exec;
852
853 groups = g_key_file_get_groups (state_file, NULL((void*)0));
854 for (g = 0; groups[g]; g++)
855 {
856 keys = g_key_file_get_keys (state_file, groups[g], NULL((void*)0), NULL((void*)0));
857 for (k = 0; keys[k]; k++)
858 {
859 value = g_key_file_get_value (state_file, groups[g],
860 keys[k], NULL((void*)0));
861 if (value)
862 {
863 g_key_file_set_value (merged_file, groups[g],
864 keys[k], value);
865 g_free (value);
866 }
867 }
868 g_strfreev (keys);
869 }
870 g_strfreev (groups);
871
872 g_key_file_free (state_file);
873 state_file = merged_file;
874
875 /* Update Exec key using "--sm-client-state-file %k" */
876 restart = generate_command (xsmp->restart_command,
877 NULL((void*)0), "%k");
878 for (i = 0; i < restart->len; i++)
879 restart->pdata[i] = g_shell_quote (restart->pdata[i]);
880 g_ptr_array_add (restart, NULL((void*)0));
881 exec = g_strjoinv (" ", (char **)restart->pdata);
882 g_strfreev ((char **)restart->pdata);
883 g_ptr_array_free (restart, FALSE(0));
884
885 g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP"Desktop Entry",
886 EGG_DESKTOP_FILE_KEY_EXEC"Exec",
887 exec);
888 g_free (exec);
889 }
890 else
891 desktop_file = NULL((void*)0);
892
893 g_free (desktop_file_path);
894 }
895
896 /* Now write state_file to disk. (We can't use mktemp(), because
897 * that requires the filename to end with "XXXXXX", and we want
898 * it to end with ".desktop".)
899 */
900
901 data = g_key_file_to_data (state_file, NULL((void*)0), NULL((void*)0));
902 g_key_file_free (state_file);
903
904 offset = 0;
905 while (1)
906 {
907 state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s",
908 g_get_user_config_dir (),
909 G_DIR_SEPARATOR'/', G_DIR_SEPARATOR'/',
910 g_get_prgname (),
911 (long)time (NULL((void*)0)) + offset,
912 desktop_file ? "desktop" : "state");
913
914 fd = open (state_file_path, O_WRONLY01 | O_CREAT0100 | O_EXCL0200, 0644);
915 if (fd == -1)
916 {
917 if (errno(*__errno_location ()) == EEXIST17)
918 {
919 offset++;
920 g_free (state_file_path);
921 continue;
922 }
923 else if (errno(*__errno_location ()) == ENOTDIR20 || errno(*__errno_location ()) == ENOENT2)
924 {
925 char *sep = strrchr (state_file_path, G_DIR_SEPARATOR'/');
926
927 *sep = '\0';
928 if (g_mkdir_with_parents (state_file_path, 0755) != 0)
929 {
930 g_warning ("Could not create directory '%s'",
931 state_file_path);
932 g_free (state_file_path);
933 state_file_path = NULL((void*)0);
934 break;
935 }
936
937 continue;
938 }
939
940 g_warning ("Could not create file '%s': %s",
941 state_file_path, g_strerror (errno(*__errno_location ())));
942 g_free (state_file_path);
943 state_file_path = NULL((void*)0);
944 break;
945 }
946
947 close (fd);
948 g_file_set_contents (state_file_path, data, -1, NULL((void*)0));
949 break;
950 }
951 g_free (data);
952
953 restart = generate_command (xsmp->restart_command, xsmp->client_id,
954 state_file_path);
955 set_properties (xsmp,
956 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
957 NULL((void*)0));
958 g_ptr_array_free (restart, TRUE(!(0)));
959
960 if (state_file_path)
961 {
962 set_properties (xsmp,
963 array_prop (SmDiscardCommand"DiscardCommand",
964 "/bin/rm", "-rf", state_file_path,
965 NULL((void*)0)),
966 NULL((void*)0));
967 g_free (state_file_path);
968 }
969}
970
971static void
972xsmp_interact (SmcConn smc_conn,
973 SmPointer client_data)
974{
975 EggSMClientXSMP *xsmp = client_data;
976 EggSMClient *client = client_data;
977
978 g_debug ("Received Interact message in state %s",
979 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
980
981 if (xsmp->state != XSMP_STATE_INTERACT_REQUEST)
982 {
983 fix_broken_state (xsmp, "Interact", TRUE(!(0)), TRUE(!(0)));
984 return;
985 }
986
987 xsmp->state = XSMP_STATE_INTERACT;
988 egg_sm_client_quit_requested (client);
989}
990
991static void
992xsmp_die (SmcConn smc_conn,
993 SmPointer client_data)
994{
995 EggSMClientXSMP *xsmp = client_data;
996 EggSMClient *client = client_data;
997
998 g_debug ("Received Die message in state %s",
999 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1000
1001 sm_client_xsmp_disconnect (xsmp);
1002 egg_sm_client_quit (client);
1003}
1004
1005static void
1006xsmp_save_complete (SmcConn smc_conn,
1007 SmPointer client_data)
1008{
1009 EggSMClientXSMP *xsmp = client_data;
1010
1011 g_debug ("Received SaveComplete message in state %s",
1012 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1013
1014 if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
1015 xsmp->state = XSMP_STATE_IDLE;
1016 else
1017 fix_broken_state (xsmp, "SaveComplete", FALSE(0), FALSE(0));
1018}
1019
1020static void
1021xsmp_shutdown_cancelled (SmcConn smc_conn,
1022 SmPointer client_data)
1023{
1024 EggSMClientXSMP *xsmp = client_data;
1025 EggSMClient *client = client_data;
1026
1027 g_debug ("Received ShutdownCancelled message in state %s",
1028 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1029
1030 xsmp->shutting_down = FALSE(0);
1031
1032 if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
1033 {
1034 /* We've finished interacting and now the SM has agreed to
1035 * cancel the shutdown.
1036 */
1037 xsmp->state = XSMP_STATE_IDLE;
1038 egg_sm_client_quit_cancelled (client);
1039 }
1040 else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
1041 {
1042 /* Hm... ok, so we got a shutdown SaveYourself, which got
1043 * cancelled, but the application was still interacting, so we
1044 * didn't tell it yet, and then *another* SaveYourself arrived,
1045 * which we must still be waiting to tell the app about, except
1046 * that now that SaveYourself has been cancelled too! Dizzy yet?
1047 */
1048 xsmp->waiting_to_save_myself = FALSE(0);
1049 update_pending_events (xsmp);
1050 }
1051 else
1052 {
1053 g_debug ("Sending SaveYourselfDone(False)");
1054 SmcSaveYourselfDone (xsmp->connection, False0);
1055
1056 if (xsmp->state == XSMP_STATE_INTERACT)
1057 {
1058 /* The application is currently interacting, so we can't
1059 * tell it about the cancellation yet; we will wait until
1060 * after it calls egg_sm_client_will_quit().
1061 */
1062 xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED;
1063 }
1064 else
1065 {
1066 /* The shutdown was cancelled before the application got a
1067 * chance to interact.
1068 */
1069 xsmp->state = XSMP_STATE_IDLE;
1070 }
1071 }
1072}
1073
1074/* Utilities */
1075
1076/* Create a restart/clone/Exec command based on @restart_command.
1077 * If @client_id is non-%NULL, add "--sm-client-id @client_id".
1078 * If @state_file is non-%NULL, add "--sm-client-state-file @state_file".
1079 *
1080 * None of the input strings are g_strdup()ed; the caller must keep
1081 * them around until it is done with the returned GPtrArray, and must
1082 * then free the array, but not its contents.
1083 */
1084static GPtrArray *
1085generate_command (char **restart_command, const char *client_id,
1086 const char *state_file)
1087{
1088 GPtrArray *cmd;
1089 int i;
1090
1091 cmd = g_ptr_array_new ();
1092 g_ptr_array_add (cmd, restart_command[0]);
1093
1094 if (client_id)
1095 {
1096 g_ptr_array_add (cmd, (char *)"--sm-client-id");
1097 g_ptr_array_add (cmd, (char *)client_id);
1098 }
1099
1100 if (state_file)
1101 {
1102 g_ptr_array_add (cmd, (char *)"--sm-client-state-file");
1103 g_ptr_array_add (cmd, (char *)state_file);
1104 }
1105
1106 for (i = 1; restart_command[i]; i++)
1107 g_ptr_array_add (cmd, restart_command[i]);
1108
1109 return cmd;
1110}
1111
1112/* Takes a NULL-terminated list of SmProp * values, created by
1113 * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and
1114 * frees them.
1115 */
1116static void
1117set_properties (EggSMClientXSMP *xsmp, ...)
1118{
1119 GPtrArray *props;
1120 SmProp *prop;
1121 va_list ap;
1122 guint i;
1123
1124 props = g_ptr_array_new ();
1125
1126 va_start (ap, xsmp)__builtin_va_start(ap, xsmp);
1127 while ((prop = va_arg (ap, SmProp *)__builtin_va_arg(ap, SmProp *)))
1128 g_ptr_array_add (props, prop);
1129 va_end (ap)__builtin_va_end(ap);
1130
1131 if (xsmp->connection)
1132 {
1133 SmcSetProperties (xsmp->connection, props->len,
1134 (SmProp **)props->pdata);
1135 }
1136
1137 for (i = 0; i < props->len; i++)
1138 {
1139 prop = props->pdata[i];
1140 g_free (prop->vals);
1141 g_free (prop);
1142 }
1143 g_ptr_array_free (props, TRUE(!(0)));
1144}
1145
1146/* Takes a NULL-terminated list of property names and deletes them. */
1147static void
1148delete_properties (EggSMClientXSMP *xsmp, ...)
1149{
1150 GPtrArray *props;
1151 char *prop;
1152 va_list ap;
1153
1154 if (!xsmp->connection)
1155 return;
1156
1157 props = g_ptr_array_new ();
1158
1159 va_start (ap, xsmp)__builtin_va_start(ap, xsmp);
1160 while ((prop = va_arg (ap, char *)__builtin_va_arg(ap, char *)))
1161 g_ptr_array_add (props, prop);
1162 va_end (ap)__builtin_va_end(ap);
1163
1164 SmcDeleteProperties (xsmp->connection, props->len,
1165 (char **)props->pdata);
1166
1167 g_ptr_array_free (props, TRUE(!(0)));
1168}
1169
1170/* Takes an array of strings and creates a LISTofARRAY8 property. The
1171 * strings are neither dupped nor freed; they need to remain valid
1172 * until you're done with the SmProp.
1173 */
1174static SmProp *
1175array_prop (const char *name, ...)
1176{
1177 SmProp *prop;
1178 SmPropValue pv;
1179 GArray *vals;
1180 char *value;
1181 va_list ap;
1182
1183 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1184 prop->name = (char *)name;
1185 prop->type = (char *)SmLISTofARRAY8"LISTofARRAY8";
1186
1187 vals = g_array_new (FALSE(0), FALSE(0), sizeof (SmPropValue));
1188
1189 va_start (ap, name)__builtin_va_start(ap, name);
1190 while ((value = va_arg (ap, char *)__builtin_va_arg(ap, char *)))
1191 {
1192 pv.length = strlen (value);
1193 pv.value = value;
1194 g_array_append_val (vals, pv)g_array_append_vals (vals, &(pv), 1);
1195 }
1196 va_end (ap)__builtin_va_end(ap);
1197
1198 prop->num_vals = vals->len;
1199 prop->vals = (SmPropValue *)vals->data;
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
1200
1201 g_array_free (vals, FALSE(0));
1202
1203 return prop;
1204}
1205
1206/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property.
1207 * The array contents are neither dupped nor freed; they need to
1208 * remain valid until you're done with the SmProp.
1209 */
1210static SmProp *
1211ptrarray_prop (const char *name, GPtrArray *values)
1212{
1213 SmProp *prop;
1214 SmPropValue pv;
1215 GArray *vals;
1216 guint i;
1217
1218 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1219 prop->name = (char *)name;
1220 prop->type = (char *)SmLISTofARRAY8"LISTofARRAY8";
1221
1222 vals = g_array_new (FALSE(0), FALSE(0), sizeof (SmPropValue));
1223
1224 for (i = 0; i < values->len; i++)
1225 {
1226 pv.length = strlen (values->pdata[i]);
1227 pv.value = values->pdata[i];
1228 g_array_append_val (vals, pv)g_array_append_vals (vals, &(pv), 1);
1229 }
1230
1231 prop->num_vals = vals->len;
1232 prop->vals = (SmPropValue *)vals->data;
1233
1234 g_array_free (vals, FALSE(0));
1235
1236 return prop;
1237}
1238
1239/* Takes a string and creates an ARRAY8 property. The string is
1240 * neither dupped nor freed; it needs to remain valid until you're
1241 * done with the SmProp.
1242 */
1243static SmProp *
1244string_prop (const char *name, const char *value)
1245{
1246 SmProp *prop;
1247
1248 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1249 prop->name = (char *)name;
1250 prop->type = (char *)SmARRAY8"ARRAY8";
1251
1252 prop->num_vals = 1;
1253 prop->vals = g_new (SmPropValue, 1)((SmPropValue *) g_malloc_n ((1), sizeof (SmPropValue)));
1254
1255 prop->vals[0].length = strlen (value);
1256 prop->vals[0].value = (char *)value;
1257
1258 return prop;
1259}
1260
1261/* Takes a char and creates a CARD8 property. */
1262static SmProp *
1263card8_prop (const char *name, unsigned char value)
1264{
1265 SmProp *prop;
1266 char *card8val;
1267
1268 /* To avoid having to allocate and free prop->vals[0], we cheat and
1269 * make vals a 2-element-long array and then use the second element
1270 * to store value.
1271 */
1272
1273 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1274 prop->name = (char *)name;
1275 prop->type = (char *)SmCARD8"CARD8";
1276
1277 prop->num_vals = 1;
1278 prop->vals = g_new (SmPropValue, 2)((SmPropValue *) g_malloc_n ((2), sizeof (SmPropValue)));
1279 card8val = (char *)(&prop->vals[1]);
1280 card8val[0] = value;
1281
1282 prop->vals[0].length = 1;
1283 prop->vals[0].value = card8val;
1284
1285 return prop;
1286}
1287
1288/* ICE code. This makes no effort to play nice with anyone else trying
1289 * to use libICE. Fortunately, no one uses libICE for anything other
1290 * than SM. (DCOP uses ICE, but it has its own private copy of
1291 * libICE.)
1292 *
1293 * When this moves to gtk, it will need to be cleverer, to avoid
1294 * tripping over old apps that use MateClient or that use libSM
1295 * directly.
1296 */
1297
1298#include <X11/ICE/ICElib.h>
1299#include <fcntl.h>
1300
1301static void ice_error_handler (IceConn ice_conn,
1302 Boolint swap,
1303 int offending_minor_opcode,
1304 unsigned long offending_sequence,
1305 int error_class,
1306 int severity,
1307 IcePointer values);
1308static void ice_io_error_handler (IceConn ice_conn);
1309static void ice_connection_watch (IceConn ice_conn,
1310 IcePointer client_data,
1311 Boolint opening,
1312 IcePointer *watch_data);
1313
1314static void
1315ice_init (void)
1316{
1317 IceSetIOErrorHandler (ice_io_error_handler);
1318 IceSetErrorHandler (ice_error_handler);
1319 IceAddConnectionWatch (ice_connection_watch, NULL((void*)0));
1320}
1321
1322static gboolean
1323process_ice_messages (IceConn ice_conn)
1324{
1325 IceProcessMessagesStatus status;
1326 status = IceProcessMessages (ice_conn, NULL((void*)0), NULL((void*)0));
1327
1328 switch (status)
1329 {
1330 case IceProcessMessagesSuccess:
1331 return TRUE(!(0));
1332
1333 case IceProcessMessagesIOError:
1334 sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn));
1335 return FALSE(0);
1336
1337 case IceProcessMessagesConnectionClosed:
1338 return FALSE(0);
1339
1340 default:
1341 g_assert_not_reached ()do { g_assertion_message_expr ("EggSMClient", "eggsmclient-xsmp.c"
, 1341, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1342 }
1343}
1344
1345static gboolean
1346ice_iochannel_watch (GIOChannel *channel,
1347 GIOCondition condition,
1348 gpointer client_data)
1349{
1350 return process_ice_messages (client_data);
1351}
1352
1353static void
1354ice_connection_watch (IceConn ice_conn,
1355 IcePointer client_data,
1356 Boolint opening,
1357 IcePointer *watch_data)
1358{
1359 guint watch_id;
1360
1361 if (opening)
1362 {
1363 GIOChannel *channel;
1364 int fd = IceConnectionNumber (ice_conn);
1365
1366 fcntl (fd, F_SETFD2, fcntl (fd, F_GETFD1, 0) | FD_CLOEXEC1);
1367 channel = g_io_channel_unix_new (fd);
1368 watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR,
1369 ice_iochannel_watch, ice_conn);
1370 g_io_channel_unref (channel);
1371
1372 *watch_data = GUINT_TO_POINTER (watch_id)((gpointer) (gulong) (watch_id));
1373 }
1374 else
1375 {
1376 watch_id = GPOINTER_TO_UINT (*watch_data)((guint) (gulong) (*watch_data));
1377 g_source_remove (watch_id);
1378 }
1379}
1380
1381static void
1382ice_error_handler (IceConn ice_conn,
1383 Boolint swap,
1384 int offending_minor_opcode,
1385 unsigned long offending_sequence,
1386 int error_class,
1387 int severity,
1388 IcePointer values)
1389{
1390 /* Do nothing */
1391}
1392
1393static void
1394ice_io_error_handler (IceConn ice_conn)
1395{
1396 /* Do nothing */
1397}
1398
1399static void
1400smc_error_handler (SmcConn smc_conn,
1401 Boolint swap,
1402 int offending_minor_opcode,
1403 unsigned long offending_sequence,
1404 int error_class,
1405 int severity,
1406 SmPointer values)
1407{
1408 /* Do nothing */
1409}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bafe5d.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bafe5d.html new file mode 100644 index 00000000..3d42399c --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bafe5d.html @@ -0,0 +1,3648 @@ + + + +gdict-defbox.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-defbox.c
Warning:line 629, column 13
The left operand of '==' is a garbage value
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gdict-defbox.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/mate-dictionary/libgdict -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Gdict" -D DATADIR="/usr/local/share" -D LIBDIR="/usr/local/lib" -D SYSCONFDIR="/usr/local/etc" -D PREFIX="/usr/local" -D MATELOCALEDIR="/usr/local/share/locale" -D GDICTSOURCESDIR="/usr/local/share/mate-dict/sources" -D GDICT_ENABLE_INTERNALS -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D G_DISABLE_CAST_CHECKS -D PIC -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c gdict-defbox.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2005-2006 Emmanuele Bassi <ebassi@gmail.com>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20/**
21 * SECTION:gdict-defbox
22 * @short_description: Display the list of definitions for a word
23 *
24 * The #GdictDefbox widget is a composite widget showing the list of
25 * definitions for a word. It queries the passed #GdictContext and displays
26 * the list of #GdictDefinition<!-- -->s obtained.
27 *
28 * It provides syntax highlighting, clickable links and an embedded find
29 * bar.
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 <stdarg.h>
40
41#include <gtk/gtk.h>
42#include <gdk/gdkkeysyms.h>
43#include <glib/gi18n-lib.h>
44
45#include "gdict-defbox.h"
46#include "gdict-utils.h"
47#include "gdict-debug.h"
48#include "gdict-private.h"
49#include "gdict-enum-types.h"
50#include "gdict-marshal.h"
51
52#define QUERY_MARGIN48 48
53#define ERROR_MARGIN24 24
54
55typedef struct
56{
57 GdictDefinition *definition;
58
59 gint begin;
60} Definition;
61
62struct _GdictDefboxPrivate
63{
64 GtkWidget *text_view;
65
66 /* the "find" pane */
67 GtkWidget *find_pane;
68 GtkWidget *find_entry;
69 GtkWidget *find_next;
70 GtkWidget *find_prev;
71 GtkWidget *find_label;
72
73 GtkWidget *progress_dialog;
74
75 GtkTextBuffer *buffer;
76
77 GdictContext *context;
78 GSList *definitions;
79
80 gchar *word;
81 gchar *database;
82 gchar *font_name;
83
84 guint show_find : 1;
85 guint is_searching : 1;
86 guint is_hovering : 1;
87
88 GdkCursor *busy_cursor;
89 GdkCursor *hand_cursor;
90 GdkCursor *regular_cursor;
91
92 guint start_id;
93 guint end_id;
94 guint define_id;
95 guint error_id;
96 guint hide_timeout;
97
98 GtkTextTag *link_tag;
99 GtkTextTag *visited_link_tag;
100};
101
102enum
103{
104 PROP_0,
105
106 PROP_CONTEXT,
107 PROP_WORD,
108 PROP_DATABASE,
109 PROP_FONT_NAME,
110 PROP_COUNT
111};
112
113enum
114{
115 SHOW_FIND,
116 HIDE_FIND,
117 FIND_NEXT,
118 FIND_PREVIOUS,
119 LINK_CLICKED,
120
121 LAST_SIGNAL
122};
123
124static guint gdict_defbox_signals[LAST_SIGNAL] = { 0 };
125
126G_DEFINE_TYPE_WITH_PRIVATE (GdictDefbox, gdict_defbox, GTK_TYPE_BOX)static void gdict_defbox_init (GdictDefbox *self); static void
gdict_defbox_class_init (GdictDefboxClass *klass); static GType
gdict_defbox_get_type_once (void); static gpointer gdict_defbox_parent_class
= ((void*)0); static gint GdictDefbox_private_offset; static
void gdict_defbox_class_intern_init (gpointer klass) { gdict_defbox_parent_class
= g_type_class_peek_parent (klass); if (GdictDefbox_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictDefbox_private_offset
); gdict_defbox_class_init ((GdictDefboxClass*) klass); } __attribute__
((__unused__)) static inline gpointer gdict_defbox_get_instance_private
(GdictDefbox *self) { return (((gpointer) ((guint8*) (self) +
(glong) (GdictDefbox_private_offset)))); } GType gdict_defbox_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_defbox_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_defbox_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_box_get_type ()), g_intern_static_string ("GdictDefbox"
), sizeof (GdictDefboxClass), (GClassInitFunc)(void (*)(void)
) gdict_defbox_class_intern_init, sizeof (GdictDefbox), (GInstanceInitFunc
)(void (*)(void)) gdict_defbox_init, (GTypeFlags) 0); { {{ GdictDefbox_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (GdictDefboxPrivate
)); };} } return g_define_type_id; }
127
128static Definition *
129definition_new (void)
130{
131 Definition *def;
132
133 def = g_slice_new (Definition)((Definition*) g_slice_alloc (sizeof (Definition)));
134 def->definition = NULL((void*)0);
135 def->begin = -1;
136
137 return def;
138}
139
140static void
141definition_free (Definition *def)
142{
143 if (!def)
144 return;
145
146 gdict_definition_unref (def->definition);
147 g_slice_free (Definition, def)do { if (1) g_slice_free1 (sizeof (Definition), (def)); else (
void) ((Definition*) 0 == (def)); } while (0)
;
148}
149
150static void
151gdict_defbox_dispose (GObject *gobject)
152{
153 GdictDefbox *defbox = GDICT_DEFBOX (gobject)((((GdictDefbox*) (void *) ((gobject)))));
154 GdictDefboxPrivate *priv = defbox->priv;
155
156 if (priv->start_id)
157 {
158 g_signal_handler_disconnect (priv->context, priv->start_id);
159 g_signal_handler_disconnect (priv->context, priv->end_id);
160 g_signal_handler_disconnect (priv->context, priv->define_id);
161
162 priv->start_id = 0;
163 priv->end_id = 0;
164 priv->define_id = 0;
165 }
166
167 if (priv->error_id)
168 {
169 g_signal_handler_disconnect (priv->context, priv->error_id);
170 priv->error_id = 0;
171 }
172
173 if (priv->context)
174 {
175 g_object_unref (priv->context);
176 priv->context = NULL((void*)0);
177 }
178
179 if (priv->buffer)
180 {
181 g_object_unref (priv->buffer);
182 priv->buffer = NULL((void*)0);
183 }
184
185 if (priv->busy_cursor)
186 {
187 g_object_unref (priv->busy_cursor);
188 priv->busy_cursor = NULL((void*)0);
189 }
190
191 if (priv->hand_cursor)
192 {
193 g_object_unref (priv->hand_cursor);
194 priv->hand_cursor = NULL((void*)0);
195 }
196
197 if (priv->regular_cursor)
198 {
199 g_object_unref (priv->regular_cursor);
200 priv->regular_cursor = NULL((void*)0);
201 }
202
203 g_clear_pointer (&priv->word, g_free)do { _Static_assert (sizeof *(&priv->word) == sizeof (
gpointer), "Expression evaluates to false"); __typeof__ ((&
priv->word)) _pp = (&priv->word); __typeof__ (*(&
priv->word)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free
) (_ptr); } while (0)
;
204
205 G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->dispose (gobject);
206}
207
208static void
209gdict_defbox_finalize (GObject *object)
210{
211 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
212 GdictDefboxPrivate *priv = defbox->priv;
213
214 g_free (priv->database);
215 g_free (priv->word);
216 g_free (priv->font_name);
217
218 if (priv->definitions)
219 {
220 g_slist_free_full (priv->definitions, (GDestroyNotify) definition_free);
221 priv->definitions = NULL((void*)0);
222 }
223
224 G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->finalize (object);
225}
226
227static void
228set_gdict_context (GdictDefbox *defbox,
229 GdictContext *context)
230{
231 GdictDefboxPrivate *priv;
232
233 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
234
235 priv = defbox->priv;
236 if (priv->context)
237 {
238 if (priv->start_id)
239 {
240 GDICT_NOTE (DEFBOX, "Removing old context handlers");
241
242 g_signal_handler_disconnect (priv->context, priv->start_id);
243 g_signal_handler_disconnect (priv->context, priv->define_id);
244 g_signal_handler_disconnect (priv->context, priv->end_id);
245
246 priv->start_id = 0;
247 priv->end_id = 0;
248 priv->define_id = 0;
249 }
250
251 if (priv->error_id)
252 {
253 g_signal_handler_disconnect (priv->context, priv->error_id);
254
255 priv->error_id = 0;
256 }
257
258 GDICT_NOTE (DEFBOX, "Removing old context");
259
260 g_object_unref (G_OBJECT (priv->context)((((GObject*) (void *) ((priv->context))))));
261 }
262
263 if (!context)
264 return;
265
266 if (!GDICT_IS_CONTEXT (context)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(context)); GType __t = ((gdict_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
267 {
268 g_warning ("Object of type '%s' instead of a GdictContext\n",
269 g_type_name (G_OBJECT_TYPE (context)(((((GTypeClass*) (((GTypeInstance*) (context))->g_class))
->g_type)))
));
270 return;
271 }
272
273 GDICT_NOTE (DEFBOX, "Setting new context");
274
275 priv->context = context;
276 g_object_ref (G_OBJECT (priv->context))((__typeof__ (((((GObject*) (void *) ((priv->context))))))
) (g_object_ref) (((((GObject*) (void *) ((priv->context))
)))))
;
277}
278
279static void
280gdict_defbox_set_property (GObject *object,
281 guint prop_id,
282 const GValue *value,
283 GParamSpec *pspec)
284{
285 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
286 GdictDefboxPrivate *priv = defbox->priv;
287
288 switch (prop_id)
289 {
290 case PROP_WORD:
291 gdict_defbox_lookup (defbox, g_value_get_string (value));
292 break;
293 case PROP_CONTEXT:
294 set_gdict_context (defbox, g_value_get_object (value));
295 break;
296 case PROP_DATABASE:
297 g_free (priv->database);
298 priv->database = g_strdup (g_value_get_string (value))g_strdup_inline (g_value_get_string (value));
299 break;
300 case PROP_FONT_NAME:
301 gdict_defbox_set_font_name (defbox, g_value_get_string (value));
302 break;
303 default:
304 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-defbox.c", 304, ("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)
;
305 break;
306 }
307}
308
309static void
310gdict_defbox_get_property (GObject *object,
311 guint prop_id,
312 GValue *value,
313 GParamSpec *pspec)
314{
315 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
316 GdictDefboxPrivate *priv = defbox->priv;
317
318 switch (prop_id)
319 {
320 case PROP_WORD:
321 g_value_set_string (value, priv->word);
322 break;
323 case PROP_CONTEXT:
324 g_value_set_object (value, priv->context);
325 break;
326 case PROP_DATABASE:
327 g_value_set_string (value, priv->database);
328 break;
329 case PROP_FONT_NAME:
330 g_value_set_string (value, priv->font_name);
331 break;
332 default:
333 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-defbox.c", 333, ("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)
;
334 break;
335 }
336}
337
338/*
339 * this code has been copied from gtksourceview; it's the implementation
340 * for case-insensitive search in a GtkTextBuffer. this is non-trivial, as
341 * searches on a utf-8 text stream involve a norm(casefold(norm(utf8)))
342 * operation which can be costly on large buffers. luckily for us, it's
343 * not the case on a set of definitions.
344 */
345
346#define GTK_TEXT_UNKNOWN_CHAR0xFFFC 0xFFFC
347
348/* this function acts like g_utf8_offset_to_pointer() except that if it finds a
349 * decomposable character it consumes the decomposition length from the given
350 * offset. So it's useful when the offset was calculated for the normalized
351 * version of str, but we need a pointer to str itself. */
352static const gchar *
353pointer_from_offset_skipping_decomp (const gchar *str, gint offset)
354{
355 gchar *casefold, *normal;
356 const gchar *p, *q;
357
358 p = str;
359 while (offset > 0)
360 {
361 q = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
362 casefold = g_utf8_casefold (p, q - p);
363 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
364 offset -= g_utf8_strlen (normal, -1);
365 g_free (casefold);
366 g_free (normal);
367 p = q;
368 }
369 return p;
370}
371
372static gboolean
373exact_prefix_cmp (const gchar *string,
374 const gchar *prefix,
375 guint prefix_len)
376{
377 GUnicodeType type;
378
379 if (strncmp (string, prefix, prefix_len) != 0)
380 return FALSE(0);
381 if (string[prefix_len] == '\0')
382 return TRUE(!(0));
383
384 type = g_unichar_type (g_utf8_get_char (string + prefix_len));
385
386 /* If string contains prefix, check that prefix is not followed
387 * by a unicode mark symbol, e.g. that trailing 'a' in prefix
388 * is not part of two-char a-with-hat symbol in string. */
389 return type != G_UNICODE_SPACING_MARK &&
390 type != G_UNICODE_ENCLOSING_MARK &&
391 type != G_UNICODE_NON_SPACING_MARK;
392}
393
394static const gchar *
395utf8_strcasestr (const gchar *haystack, const gchar *needle)
396{
397 gsize needle_len;
398 gsize haystack_len;
399 const gchar *ret = NULL((void*)0);
400 gchar *p;
401 gchar *casefold;
402 gchar *caseless_haystack;
403 gint i;
404
405 g_return_val_if_fail (haystack != NULL, NULL)do{ (void)0; }while (0);
406 g_return_val_if_fail (needle != NULL, NULL)do{ (void)0; }while (0);
407
408 casefold = g_utf8_casefold (haystack, -1);
409 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
410 g_free (casefold);
411
412 needle_len = g_utf8_strlen (needle, -1);
413 haystack_len = g_utf8_strlen (caseless_haystack, -1);
414
415 if (needle_len == 0)
416 {
417 ret = (gchar *)haystack;
418 goto finally_1;
419 }
420
421 if (haystack_len < needle_len)
422 {
423 ret = NULL((void*)0);
424 goto finally_1;
425 }
426
427 p = (gchar*)caseless_haystack;
428 needle_len = strlen (needle);
429 i = 0;
430
431 while (*p)
432 {
433 if (exact_prefix_cmp (p, needle, needle_len))
434 {
435 ret = pointer_from_offset_skipping_decomp (haystack, i);
436 goto finally_1;
437 }
438
439 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
440 i++;
441 }
442
443finally_1:
444 g_free (caseless_haystack);
445
446 return ret;
447}
448
449static const gchar *
450utf8_strrcasestr (const gchar *haystack, const gchar *needle)
451{
452 gsize needle_len;
453 gsize haystack_len;
454 const gchar *ret = NULL((void*)0);
455 gchar *p;
456 gchar *casefold;
457 gchar *caseless_haystack;
458 gint i;
459
460 g_return_val_if_fail (haystack != NULL, NULL)do{ (void)0; }while (0);
461 g_return_val_if_fail (needle != NULL, NULL)do{ (void)0; }while (0);
462
463 casefold = g_utf8_casefold (haystack, -1);
464 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
465 g_free (casefold);
466
467 needle_len = g_utf8_strlen (needle, -1);
468 haystack_len = g_utf8_strlen (caseless_haystack, -1);
469
470 if (needle_len == 0)
471 {
472 ret = (gchar *)haystack;
473 goto finally_1;
474 }
475
476 if (haystack_len < needle_len)
477 {
478 ret = NULL((void*)0);
479 goto finally_1;
480 }
481
482 i = haystack_len - needle_len;
483 p = g_utf8_offset_to_pointer (caseless_haystack, i);
484 needle_len = strlen (needle);
485
486 while (p >= caseless_haystack)
487 {
488 if (exact_prefix_cmp (p, needle, needle_len))
489 {
490 ret = pointer_from_offset_skipping_decomp (haystack, i);
491 goto finally_1;
492 }
493
494 p = g_utf8_prev_char (p);
495 i--;
496 }
497
498finally_1:
499 g_free (caseless_haystack);
500
501 return ret;
502}
503
504static gboolean
505utf8_caselessnmatch (const char *s1, const char *s2,
506 gssize n1, gssize n2)
507{
508 gchar *casefold;
509 gchar *normalized_s1;
510 gchar *normalized_s2;
511 gint len_s1;
512 gint len_s2;
513 gboolean ret = FALSE(0);
514
515 g_return_val_if_fail (s1 != NULL, FALSE)do{ (void)0; }while (0);
516 g_return_val_if_fail (s2 != NULL, FALSE)do{ (void)0; }while (0);
517 g_return_val_if_fail (n1 > 0, FALSE)do{ (void)0; }while (0);
518 g_return_val_if_fail (n2 > 0, FALSE)do{ (void)0; }while (0);
519
520 casefold = g_utf8_casefold (s1, n1);
521 normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
522 g_free (casefold);
523
524 casefold = g_utf8_casefold (s2, n2);
525 normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
526 g_free (casefold);
527
528 len_s1 = strlen (normalized_s1);
529 len_s2 = strlen (normalized_s2);
530
531 if (len_s1 < len_s2)
532 goto finally_2;
533
534 ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
535
536finally_2:
537 g_free (normalized_s1);
538 g_free (normalized_s2);
539
540 return ret;
541}
542
543/* FIXME: total horror */
544static gboolean
545char_is_invisible (const GtkTextIter *iter)
546{
547 GSList *tags;
548 gboolean invisible = FALSE(0);
549 tags = gtk_text_iter_get_tags (iter);
550 while (tags)
551 {
552 gboolean this_invisible, invisible_set;
553 g_object_get (tags->data, "invisible", &this_invisible,
554 "invisible-set", &invisible_set, NULL((void*)0));
555 if (invisible_set)
556 invisible = this_invisible;
557 tags = g_slist_delete_link (tags, tags);
558 }
559 return invisible;
560}
561
562static void
563forward_chars_with_skipping (GtkTextIter *iter,
564 gint count,
565 gboolean skip_invisible,
566 gboolean skip_nontext,
567 gboolean skip_decomp)
568{
569 gint i;
570
571 g_return_if_fail (count >= 0)do{ (void)0; }while (0);
572
573 i = count;
574
575 while (i > 0)
576 {
577 gboolean ignored = FALSE(0);
578
579 /* minimal workaround to avoid the infinite loop of bug #168247.
580 * It doesn't fix the problemjust the symptom...
581 */
582 if (gtk_text_iter_is_end (iter))
583 return;
584
585 if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR0xFFFC)
586 ignored = TRUE(!(0));
587
588 /* FIXME: char_is_invisible() gets list of tags for each char there,
589 and checks every tag. It doesn't sound like a good idea. */
590 if (!ignored && skip_invisible && char_is_invisible (iter))
591 ignored = TRUE(!(0));
592
593 if (!ignored && skip_decomp)
594 {
595 /* being UTF8 correct sucks; this accounts for extra
596 offsets coming from canonical decompositions of
597 UTF8 characters (e.g. accented characters) which
598 g_utf8_normalize() performs */
599 gchar *normal;
600 gchar buffer[6];
601 gint buffer_len;
602
603 buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
604 normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD);
605 i -= (g_utf8_strlen (normal, -1) - 1);
606 g_free (normal);
607 }
608
609 gtk_text_iter_forward_char (iter);
610
611 if (!ignored)
612 --i;
613 }
614}
615
616static gboolean
617lines_match (const GtkTextIter *start,
618 const gchar **lines,
619 gboolean visible_only,
620 gboolean slice,
621 GtkTextIter *match_start,
622 GtkTextIter *match_end)
623{
624 GtkTextIter next;
625 gchar *line_text;
626 const gchar *found;
627 gint offset;
628
629 if (*lines == NULL((void*)0) || **lines == '\0')
23
The left operand of '==' is a garbage value
630 {
631 if (match_start)
632 *match_start = *start;
633 if (match_end)
634 *match_end = *start;
635 return TRUE(!(0));
636 }
637
638 next = *start;
639 gtk_text_iter_forward_line (&next);
640
641 /* No more text in buffer, but *lines is nonempty */
642 if (gtk_text_iter_equal (start, &next))
643 return FALSE(0);
644
645 if (slice)
646 {
647 if (visible_only)
648 line_text = gtk_text_iter_get_visible_slice (start, &next);
649 else
650 line_text = gtk_text_iter_get_slice (start, &next);
651 }
652 else
653 {
654 if (visible_only)
655 line_text = gtk_text_iter_get_visible_text (start, &next);
656 else
657 line_text = gtk_text_iter_get_text (start, &next);
658 }
659
660 if (match_start) /* if this is the first line we're matching */
661 {
662 found = utf8_strcasestr (line_text, *lines);
663 }
664 else
665 {
666 /* If it's not the first line, we have to match from the
667 * start of the line.
668 */
669 if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
670 strlen (*lines)))
671 found = line_text;
672 else
673 found = NULL((void*)0);
674 }
675
676 if (found == NULL((void*)0))
677 {
678 g_free (line_text);
679 return FALSE(0);
680 }
681
682 /* Get offset to start of search string */
683 offset = g_utf8_strlen (line_text, found - line_text);
684
685 next = *start;
686
687 /* If match start needs to be returned, set it to the
688 * start of the search string.
689 */
690 forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE(0));
691 if (match_start)
692 {
693 *match_start = next;
694 }
695
696 /* Go to end of search string */
697 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE(!(0)));
698
699 g_free (line_text);
700
701 ++lines;
702
703 if (match_end)
704 *match_end = next;
705
706 /* pass NULL for match_start, since we don't need to find the
707 * start again.
708 */
709 return lines_match (&next, lines, visible_only, slice, NULL((void*)0), match_end);
710}
711
712static gboolean
713backward_lines_match (const GtkTextIter *start,
714 const gchar **lines,
715 gboolean visible_only,
716 gboolean slice,
717 GtkTextIter *match_start,
718 GtkTextIter *match_end)
719{
720 GtkTextIter line, next;
721 gchar *line_text;
722 const gchar *found;
723 gint offset;
724
725 if (*lines == NULL((void*)0) || **lines == '\0')
726 {
727 if (match_start)
728 *match_start = *start;
729 if (match_end)
730 *match_end = *start;
731 return TRUE(!(0));
732 }
733
734 line = next = *start;
735 if (gtk_text_iter_get_line_offset (&next) == 0)
736 {
737 if (!gtk_text_iter_backward_line (&next))
738 return FALSE(0);
739 }
740 else
741 gtk_text_iter_set_line_offset (&next, 0);
742
743 if (slice)
744 {
745 if (visible_only)
746 line_text = gtk_text_iter_get_visible_slice (&next, &line);
747 else
748 line_text = gtk_text_iter_get_slice (&next, &line);
749 }
750 else
751 {
752 if (visible_only)
753 line_text = gtk_text_iter_get_visible_text (&next, &line);
754 else
755 line_text = gtk_text_iter_get_text (&next, &line);
756 }
757
758 if (match_start) /* if this is the first line we're matching */
759 {
760 found = utf8_strrcasestr (line_text, *lines);
761 }
762 else
763 {
764 /* If it's not the first line, we have to match from the
765 * start of the line.
766 */
767 if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
768 strlen (*lines)))
769 found = line_text;
770 else
771 found = NULL((void*)0);
772 }
773
774 if (found == NULL((void*)0))
775 {
776 g_free (line_text);
777 return FALSE(0);
778 }
779
780 /* Get offset to start of search string */
781 offset = g_utf8_strlen (line_text, found - line_text);
782
783 forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE(0));
784
785 /* If match start needs to be returned, set it to the
786 * start of the search string.
787 */
788 if (match_start)
789 {
790 *match_start = next;
791 }
792
793 /* Go to end of search string */
794 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE(!(0)));
795
796 g_free (line_text);
797
798 ++lines;
799
800 if (match_end)
801 *match_end = next;
802
803 /* try to match the rest of the lines forward, passing NULL
804 * for match_start so lines_match will try to match the entire
805 * line */
806 return lines_match (&next, lines, visible_only,
807 slice, NULL((void*)0), match_end);
808}
809
810/* strsplit () that retains the delimiter as part of the string. */
811static gchar **
812breakup_string (const char *string,
813 const char *delimiter,
814 gint max_tokens)
815{
816 GSList *string_list = NULL((void*)0), *slist;
817 gchar **str_array, *s, *casefold, *new_string;
818 guint i, n = 1;
819
820 g_return_val_if_fail (string != NULL, NULL)do{ (void)0; }while (0);
13
Loop condition is false. Exiting loop
821 g_return_val_if_fail (delimiter != NULL, NULL)do{ (void)0; }while (0);
14
Loop condition is false. Exiting loop
822
823 if (max_tokens
14.1
'max_tokens' is < 1
< 1)
15
Taking true branch
824 max_tokens = G_MAXINT2147483647;
825
826 s = strstr (string, delimiter);
827 if (s)
16
Assuming 's' is null
17
Taking false branch
828 {
829 guint delimiter_len = strlen (delimiter);
830
831 do
832 {
833 guint len;
834
835 len = s - string + delimiter_len;
836 new_string = g_new (gchar, len + 1)((gchar *) g_malloc_n ((len + 1), sizeof (gchar)));
837 strncpy (new_string, string, len);
838 new_string[len] = 0;
839 casefold = g_utf8_casefold (new_string, -1);
840 g_free (new_string);
841 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
842 g_free (casefold);
843 string_list = g_slist_prepend (string_list, new_string);
844 n++;
845 string = s + delimiter_len;
846 s = strstr (string, delimiter);
847 } while (--max_tokens && s);
848 }
849
850 if (*string)
18
Taking true branch
851 {
852 n++;
853 casefold = g_utf8_casefold (string, -1);
854 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
855 g_free (casefold);
856 string_list = g_slist_prepend (string_list, new_string);
857 }
858
859 str_array = g_new (gchar*, n)((gchar* *) g_malloc_n ((n), sizeof (gchar*)));
19
Storing uninitialized value
860
861 i = n - 1;
862
863 str_array[i--] = NULL((void*)0);
864 for (slist = string_list; slist; slist = slist->next)
20
Loop condition is false. Execution continues on line 867
865 str_array[i--] = slist->data;
866
867 g_slist_free (string_list);
868
869 return str_array;
870}
871
872static gboolean
873gdict_defbox_iter_forward_search (const GtkTextIter *iter,
874 const gchar *str,
875 GtkTextIter *match_start,
876 GtkTextIter *match_end,
877 const GtkTextIter *limit)
878{
879 gchar **lines = NULL((void*)0);
880 GtkTextIter match;
881 gboolean retval = FALSE(0);
882 GtkTextIter search;
883
884 g_return_val_if_fail (iter != NULL, FALSE)do{ (void)0; }while (0);
9
Loop condition is false. Exiting loop
885 g_return_val_if_fail (str != NULL, FALSE)do{ (void)0; }while (0);
886
887 if (limit
9.1
'limit' is null
&& gtk_text_iter_compare (iter, limit) >= 0)
888 return FALSE(0);
889
890 if (*str == '\0')
10
Assuming the condition is false
11
Taking false branch
891 {
892 /* If we can move one char, return the empty string there */
893 match = *iter;
894
895 if (gtk_text_iter_forward_char (&match))
896 {
897 if (limit && gtk_text_iter_equal (&match, limit))
898 return FALSE(0);
899
900 if (match_start)
901 *match_start = match;
902
903 if (match_end)
904 *match_end = match;
905
906 return TRUE(!(0));
907 }
908 else
909 return FALSE(0);
910 }
911
912 /* locate all lines */
913 lines = breakup_string (str, "\n", -1);
12
Calling 'breakup_string'
21
Returning from 'breakup_string'
914
915 search = *iter;
916
917 /* This loop has an inefficient worst-case, where
918 * gtk_text_iter_get_text () is called repeatedly on
919 * a single line.
920 */
921 do
922 {
923 GtkTextIter end;
924 gboolean res;
925
926 if (limit
21.1
'limit' is null
&& gtk_text_iter_compare (&search, limit) >= 0)
927 break;
928
929 res = lines_match (&search, (const gchar**)lines,
22
Calling 'lines_match'
930 TRUE(!(0)), FALSE(0),
931 &match, &end);
932 if (res)
933 {
934 if (limit == NULL((void*)0) ||
935 (limit && gtk_text_iter_compare (&end, limit) <= 0))
936 {
937 retval = TRUE(!(0));
938
939 if (match_start)
940 *match_start = match;
941
942 if (match_end)
943 *match_end = end;
944 }
945
946 break;
947 }
948 } while (gtk_text_iter_forward_line (&search));
949
950 g_strfreev ((gchar**) lines);
951
952 return retval;
953}
954
955static gboolean
956gdict_defbox_iter_backward_search (const GtkTextIter *iter,
957 const gchar *str,
958 GtkTextIter *match_start,
959 GtkTextIter *match_end,
960 const GtkTextIter *limit)
961{
962 gchar **lines = NULL((void*)0);
963 GtkTextIter match;
964 gboolean retval = FALSE(0);
965 GtkTextIter search;
966
967 g_return_val_if_fail (iter != NULL, FALSE)do{ (void)0; }while (0);
968 g_return_val_if_fail (str != NULL, FALSE)do{ (void)0; }while (0);
969
970 if (limit && gtk_text_iter_compare (iter, limit) <= 0)
971 return FALSE(0);
972
973 if (*str == '\0')
974 {
975 /* If we can move one char, return the empty string there */
976 match = *iter;
977
978 if (gtk_text_iter_backward_char (&match))
979 {
980 if (limit && gtk_text_iter_equal (&match, limit))
981 return FALSE(0);
982
983 if (match_start)
984 *match_start = match;
985
986 if (match_end)
987 *match_end = match;
988
989 return TRUE(!(0));
990 }
991 else
992 return FALSE(0);
993 }
994
995 /* locate all lines */
996 lines = breakup_string (str, "\n", -1);
997
998 search = *iter;
999
1000 /* This loop has an inefficient worst-case, where
1001 * gtk_text_iter_get_text () is called repeatedly on
1002 * a single line.
1003 */
1004 while (TRUE(!(0)))
1005 {
1006 GtkTextIter end;
1007 gboolean res;
1008
1009 if (limit && gtk_text_iter_compare (&search, limit) <= 0)
1010 break;
1011
1012 res = backward_lines_match (&search, (const gchar**)lines,
1013 TRUE(!(0)), FALSE(0),
1014 &match, &end);
1015 if (res)
1016 {
1017 if (limit == NULL((void*)0) ||
1018 (limit && gtk_text_iter_compare (&end, limit) > 0))
1019 {
1020 retval = TRUE(!(0));
1021
1022 if (match_start)
1023 *match_start = match;
1024
1025 if (match_end)
1026 *match_end = end;
1027
1028 }
1029
1030 break;
1031 }
1032
1033 if (gtk_text_iter_get_line_offset (&search) == 0)
1034 {
1035 if (!gtk_text_iter_backward_line (&search))
1036 break;
1037 }
1038 else
1039 gtk_text_iter_set_line_offset (&search, 0);
1040 }
1041
1042 g_strfreev ((gchar**) lines);
1043
1044 return retval;
1045}
1046
1047static gboolean
1048gdict_defbox_find_backward (GdictDefbox *defbox,
1049 const gchar *text)
1050{
1051 GdictDefboxPrivate *priv = defbox->priv;
1052 GtkTextIter start_iter, end_iter;
1053 GtkTextIter match_start, match_end;
1054 GtkTextIter iter;
1055 GtkTextMark *last_search;
1056 gboolean res;
1057
1058 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
1059
1060 gtk_text_buffer_get_bounds (priv->buffer, &start_iter, &end_iter);
1061
1062 /* if there already has been another result, begin from there */
1063 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-prev");
1064 if (last_search)
1065 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1066 else
1067 iter = end_iter;
1068
1069 res = gdict_defbox_iter_backward_search (&iter, text,
1070 &match_start, &match_end,
1071 NULL((void*)0));
1072 if (res)
1073 {
1074 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
1075 &match_start,
1076 0.0,
1077 TRUE(!(0)),
1078 0.0, 0.0);
1079 gtk_text_buffer_place_cursor (priv->buffer, &match_end);
1080 gtk_text_buffer_move_mark (priv->buffer,
1081 gtk_text_buffer_get_mark (priv->buffer, "selection_bound"),
1082 &match_start);
1083 gtk_text_buffer_create_mark (priv->buffer, "last-search-prev", &match_start, FALSE(0));
1084 gtk_text_buffer_create_mark (priv->buffer, "last-search-next", &match_end, FALSE(0));
1085
1086 return TRUE(!(0));
1087 }
1088
1089 return FALSE(0);
1090}
1091
1092static gboolean
1093hide_find_pane (gpointer user_data)
1094{
1095 GdictDefbox *defbox = user_data;
1096
1097 gtk_widget_hide (defbox->priv->find_pane);
1098 defbox->priv->show_find = FALSE(0);
1099
1100 gtk_widget_grab_focus (defbox->priv->text_view);
1101
1102 defbox->priv->hide_timeout = 0;
1103
1104 return FALSE(0);
1105}
1106
1107static void
1108find_prev_clicked_cb (GtkWidget *widget,
1109 gpointer user_data)
1110{
1111 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1112 GdictDefboxPrivate *priv = defbox->priv;
1113 const gchar *text;
1114 gboolean found;
1115
1116 gtk_widget_hide (priv->find_label);
1117
1118 text = gtk_entry_get_text (GTK_ENTRY (priv->find_entry)((((GtkEntry*) (void *) ((priv->find_entry))))));
1119 if (!text)
1120 return;
1121
1122 found = gdict_defbox_find_backward (defbox, text);
1123 if (!found)
1124 {
1125 gchar *str;
1126
1127 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1128 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1129 gtk_widget_show (priv->find_label);
1130
1131 g_free (str);
1132 }
1133
1134 if (priv->hide_timeout)
1135 {
1136 g_source_remove (priv->hide_timeout);
1137 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1138 }
1139}
1140
1141static gboolean
1142gdict_defbox_find_forward (GdictDefbox *defbox,
1143 const gchar *text,
1144 gboolean is_typing)
1145{
1146 GdictDefboxPrivate *priv = defbox->priv;
1147 GtkTextIter start_iter, end_iter;
1148 GtkTextIter match_start, match_end;
1149 GtkTextIter iter;
1150 GtkTextMark *last_search;
1151 gboolean res;
1152
1153 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
4
Loop condition is false. Exiting loop
1154
1155 gtk_text_buffer_get_bounds (priv->buffer, &start_iter, &end_iter);
1156
1157 if (!is_typing
4.1
'is_typing' is 1
)
5
Taking false branch
1158 {
1159 /* if there already has been another result, begin from there */
1160 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-next");
1161
1162 if (last_search)
1163 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1164 else
1165 iter = start_iter;
1166 }
1167 else
1168 {
1169 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-prev");
1170
1171 if (last_search)
6
Assuming 'last_search' is null
7
Taking false branch
1172 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1173 else
1174 iter = start_iter;
1175 }
1176
1177 res = gdict_defbox_iter_forward_search (&iter, text,
8
Calling 'gdict_defbox_iter_forward_search'
1178 &match_start,
1179 &match_end,
1180 NULL((void*)0));
1181 if (res)
1182 {
1183 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
1184 &match_start,
1185 0.0,
1186 TRUE(!(0)),
1187 0.0, 0.0);
1188 gtk_text_buffer_place_cursor (priv->buffer, &match_end);
1189 gtk_text_buffer_move_mark (priv->buffer,
1190 gtk_text_buffer_get_mark (priv->buffer, "selection_bound"),
1191 &match_start);
1192 gtk_text_buffer_create_mark (priv->buffer, "last-search-prev", &match_start, FALSE(0));
1193 gtk_text_buffer_create_mark (priv->buffer, "last-search-next", &match_end, FALSE(0));
1194
1195 return TRUE(!(0));
1196 }
1197
1198 return FALSE(0);
1199}
1200
1201static void
1202find_next_clicked_cb (GtkWidget *widget,
1203 gpointer user_data)
1204{
1205 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1206 GdictDefboxPrivate *priv = defbox->priv;
1207 const gchar *text;
1208 gboolean found;
1209
1210 gtk_widget_hide (priv->find_label);
1211
1212 text = gtk_entry_get_text (GTK_ENTRY (priv->find_entry)((((GtkEntry*) (void *) ((priv->find_entry))))));
1213 if (!text)
1214 return;
1215
1216 found = gdict_defbox_find_forward (defbox, text, FALSE(0));
1217 if (!found)
1218 {
1219 gchar *str;
1220
1221 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1222 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1223 gtk_widget_show (priv->find_label);
1224
1225 g_free (str);
1226 }
1227
1228 if (priv->hide_timeout)
1229 {
1230 g_source_remove (priv->hide_timeout);
1231 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1232 }
1233}
1234
1235static void
1236find_entry_changed_cb (GtkWidget *widget,
1237 gpointer user_data)
1238{
1239 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1240 GdictDefboxPrivate *priv = defbox->priv;
1241 gchar *text;
1242 gboolean found;
1243
1244 gtk_widget_hide (priv->find_label);
1245
1246 text = gtk_editable_get_chars (GTK_EDITABLE (widget)((((GtkEditable*) (void *) ((widget))))), 0, -1);
1247 if (!text)
1
Assuming 'text' is non-null
2
Taking false branch
1248 return;
1249
1250 found = gdict_defbox_find_forward (defbox, text, TRUE(!(0)));
3
Calling 'gdict_defbox_find_forward'
1251 if (!found)
1252 {
1253 gchar *str;
1254
1255 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1256 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1257 gtk_widget_show (priv->find_label);
1258
1259 g_free (str);
1260 }
1261
1262 g_free (text);
1263
1264 if (priv->hide_timeout)
1265 {
1266 g_source_remove (priv->hide_timeout);
1267 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1268 }
1269}
1270
1271static void
1272close_button_clicked (GtkButton *button,
1273 gpointer data)
1274{
1275 GdictDefboxPrivate *priv = GDICT_DEFBOX (data)((((GdictDefbox*) (void *) ((data)))))->priv;
1276
1277 if (priv->hide_timeout)
1278 g_source_remove (priv->hide_timeout);
1279
1280 (void) hide_find_pane (data);
1281}
1282
1283static GtkWidget *
1284create_find_pane (GdictDefbox *defbox)
1285{
1286 GdictDefboxPrivate *priv;
1287 GtkWidget *find_pane;
1288 GtkWidget *label;
1289 GtkWidget *sep;
1290 GtkWidget *hbox1, *hbox2;
1291 GtkWidget *button;
1292
1293 priv = defbox->priv;
1294
1295 find_pane = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1296 gtk_container_set_border_width (GTK_CONTAINER (find_pane)((((GtkContainer*) (void *) ((find_pane))))), 0);
1297
1298 hbox1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1299 gtk_box_pack_start (GTK_BOX (find_pane)((((GtkBox*) (void *) ((find_pane))))), hbox1, TRUE(!(0)), TRUE(!(0)), 0);
1300 gtk_widget_show (hbox1);
1301
1302 button = gtk_button_new ();
1303 gtk_button_set_relief (GTK_BUTTON (button)((((GtkButton*) (void *) ((button))))), GTK_RELIEF_NONE);
1304 gtk_button_set_image (GTK_BUTTON (button)((((GtkButton*) (void *) ((button))))),
1305 gtk_image_new_from_icon_name ("window-close",
1306 GTK_ICON_SIZE_BUTTON));
1307 g_signal_connect (button, "clicked",g_signal_connect_data ((button), ("clicked"), (((GCallback) (
close_button_clicked))), (defbox), ((void*)0), (GConnectFlags
) 0)
1308 G_CALLBACK (close_button_clicked), defbox)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
close_button_clicked))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1309 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), button, FALSE(0), FALSE(0), 0);
1310 gtk_widget_show (button);
1311
1312 hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1313 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), hbox2, TRUE(!(0)), TRUE(!(0)), 0);
1314 gtk_widget_show (hbox2);
1315
1316 label = gtk_label_new_with_mnemonic (_("F_ind:")((char *) g_dgettext ("mate-utils", "F_ind:")));
1317 gtk_box_pack_start (GTK_BOX (hbox2)((((GtkBox*) (void *) ((hbox2))))), label, FALSE(0), FALSE(0), 0);
1318
1319 priv->find_entry = gtk_entry_new ();
1320 g_signal_connect (priv->find_entry, "changed",g_signal_connect_data ((priv->find_entry), ("changed"), ((
(GCallback) (find_entry_changed_cb))), (defbox), ((void*)0), (
GConnectFlags) 0)
1321 G_CALLBACK (find_entry_changed_cb), defbox)g_signal_connect_data ((priv->find_entry), ("changed"), ((
(GCallback) (find_entry_changed_cb))), (defbox), ((void*)0), (
GConnectFlags) 0)
;
1322 gtk_box_pack_start (GTK_BOX (hbox2)((((GtkBox*) (void *) ((hbox2))))), priv->find_entry, TRUE(!(0)), TRUE(!(0)), 0);
1323 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) ((label))))), priv->find_entry);
1324
1325 sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
1326 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), sep, FALSE(0), FALSE(0), 0);
1327 gtk_widget_show (sep);
1328
1329 priv->find_prev = gtk_button_new_with_mnemonic (_("_Previous")((char *) g_dgettext ("mate-utils", "_Previous")));
1330 gtk_button_set_image (GTK_BUTTON (priv->find_prev)((((GtkButton*) (void *) ((priv->find_prev))))),
1331 gtk_image_new_from_icon_name ("go-previous",
1332 GTK_ICON_SIZE_MENU));
1333 g_signal_connect (priv->find_prev, "clicked",g_signal_connect_data ((priv->find_prev), ("clicked"), (((
GCallback) (find_prev_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
1334 G_CALLBACK (find_prev_clicked_cb), defbox)g_signal_connect_data ((priv->find_prev), ("clicked"), (((
GCallback) (find_prev_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1335 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), priv->find_prev, FALSE(0), FALSE(0), 0);
1336
1337 priv->find_next = gtk_button_new_with_mnemonic (_("_Next")((char *) g_dgettext ("mate-utils", "_Next")));
1338 gtk_button_set_image (GTK_BUTTON (priv->find_next)((((GtkButton*) (void *) ((priv->find_next))))),
1339 gtk_image_new_from_icon_name ("go-next",
1340 GTK_ICON_SIZE_MENU));
1341 g_signal_connect (priv->find_next, "clicked",g_signal_connect_data ((priv->find_next), ("clicked"), (((
GCallback) (find_next_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
1342 G_CALLBACK (find_next_clicked_cb), defbox)g_signal_connect_data ((priv->find_next), ("clicked"), (((
GCallback) (find_next_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1343 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), priv->find_next, FALSE(0), FALSE(0), 0);
1344
1345 priv->find_label = gtk_label_new (NULL((void*)0));
1346 gtk_label_set_use_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), TRUE(!(0)));
1347 gtk_box_pack_end (GTK_BOX (find_pane)((((GtkBox*) (void *) ((find_pane))))), priv->find_label, FALSE(0), FALSE(0), 0);
1348 gtk_widget_hide (priv->find_label);
1349
1350 return find_pane;
1351}
1352
1353static void
1354gdict_defbox_init_tags (GdictDefbox *defbox)
1355{
1356 GdictDefboxPrivate *priv = defbox->priv;
1357
1358 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
1359
1360 gtk_text_buffer_create_tag (priv->buffer, "italic",
1361 "style", PANGO_STYLE_ITALIC,
1362 NULL((void*)0));
1363 gtk_text_buffer_create_tag (priv->buffer, "bold",
1364 "weight", PANGO_WEIGHT_BOLD,
1365 NULL((void*)0));
1366 gtk_text_buffer_create_tag (priv->buffer, "underline",
1367 "underline", PANGO_UNDERLINE_SINGLE,
1368 NULL((void*)0));
1369
1370 gtk_text_buffer_create_tag (priv->buffer, "big",
1371 "scale", 1.6,
1372 NULL((void*)0));
1373 gtk_text_buffer_create_tag (priv->buffer, "small",
1374 "scale", PANGO_SCALE_SMALL((double)0.8333333333333),
1375 NULL((void*)0));
1376
1377 {
1378 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1379 gboolean prefer_dark = FALSE(0);
1380 GdkRGBA rgba;
1381
1382 /* HACK: we're hardcoding the Adwaita values because GtkTextTag
1383 * cannot be styled via CSS
1384 */
1385 g_object_get (settings, "gtk-application-prefer-dark-theme", &prefer_dark, NULL((void*)0));
1386
1387 if (!prefer_dark)
1388 gdk_rgba_parse (&rgba, "#2a76c6");
1389 else
1390 gdk_rgba_parse (&rgba, "#4a90d9");
1391
1392 priv->link_tag =
1393 gtk_text_buffer_create_tag (priv->buffer, "link",
1394 "underline", PANGO_UNDERLINE_SINGLE,
1395 "foreground-rgba", &rgba,
1396 NULL((void*)0));
1397
1398 if (!prefer_dark)
1399 gdk_rgba_parse (&rgba, "#215d9c");
1400 else
1401 gdk_rgba_parse (&rgba, "#2a76c6");
1402
1403 priv->visited_link_tag =
1404 gtk_text_buffer_create_tag (priv->buffer, "visited-link",
1405 "underline", PANGO_UNDERLINE_SINGLE,
1406 "foreground-rgba", &rgba,
1407 NULL((void*)0));
1408 }
1409
1410 gtk_text_buffer_create_tag (priv->buffer, "phonetic",
1411 "foreground", "dark gray",
1412 NULL((void*)0));
1413
1414 gtk_text_buffer_create_tag (priv->buffer, "query-title",
1415 "left-margin", QUERY_MARGIN48,
1416 "pixels-above-lines", 5,
1417 "pixels-below-lines", 20,
1418 NULL((void*)0));
1419 gtk_text_buffer_create_tag (priv->buffer, "query-from",
1420 "foreground", "dark gray",
1421 "scale", PANGO_SCALE_SMALL((double)0.8333333333333),
1422 "left-margin", QUERY_MARGIN48,
1423 "pixels-above-lines", 5,
1424 "pixels-below-lines", 10,
1425 NULL((void*)0));
1426
1427 gtk_text_buffer_create_tag (priv->buffer, "error-title",
1428 "foreground", "dark red",
1429 "left-margin", ERROR_MARGIN24,
1430 NULL((void*)0));
1431 gtk_text_buffer_create_tag (priv->buffer, "error-message",
1432 "left-margin", ERROR_MARGIN24,
1433 NULL((void*)0));
1434}
1435
1436static void
1437follow_if_is_link (GdictDefbox *defbox,
1438 GtkTextView *text_view,
1439 GtkTextIter *iter)
1440{
1441 GSList *tags, *l;
1442
1443 tags = gtk_text_iter_get_tags (iter);
1444
1445 for (l = tags; l != NULL((void*)0); l = l->next)
1446 {
1447 GtkTextTag *tag = l->data;
1448 gchar *name;
1449
1450 g_object_get (G_OBJECT (tag)((((GObject*) (void *) ((tag))))), "name", &name, NULL((void*)0));
1451 if (name &&
1452 (strcmp (name, "link") == 0 ||
1453 strcmp (name, "visited-link") == 0))
1454 {
1455 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
1456 GtkTextIter start, end;
1457 gchar *link_str;
1458
1459 start = *iter;
1460 end = *iter;
1461
1462 gtk_text_iter_backward_to_tag_toggle (&start, tag);
1463 gtk_text_iter_forward_to_tag_toggle (&end, tag);
1464
1465 link_str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
1466
1467 g_signal_emit (defbox, gdict_defbox_signals[LINK_CLICKED], 0, link_str);
1468
1469 g_free (link_str);
1470 g_free (name);
1471
1472 break;
1473 }
1474
1475 g_free (name);
1476 }
1477
1478 g_slist_free (tags);
1479}
1480
1481static gboolean
1482defbox_event_after_cb (GtkWidget *text_view,
1483 GdkEvent *event,
1484 GdictDefbox *defbox)
1485{
1486 GtkTextIter iter;
1487 GtkTextBuffer *buffer;
1488 GdkEventButton *button_event;
1489 gint bx, by;
1490
1491 if (event->type != GDK_BUTTON_RELEASE)
1492 return FALSE(0);
1493
1494 button_event = (GdkEventButton *) event;
1495
1496 if (button_event->button != 1)
1497 return FALSE(0);
1498
1499 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))));
1500 if (gtk_text_buffer_get_has_selection (buffer))
1501 return FALSE(0);
1502
1503 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1504 GTK_TEXT_WINDOW_WIDGET,
1505 button_event->x, button_event->y,
1506 &bx, &by);
1507
1508 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1509 &iter,
1510 bx, by);
1511
1512 follow_if_is_link (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), &iter);
1513
1514 return FALSE(0);
1515}
1516
1517static void
1518set_cursor_if_appropriate (GdictDefbox *defbox,
1519 GtkTextView *text_view,
1520 gint x,
1521 gint y)
1522{
1523 GdictDefboxPrivate *priv;
1524 GSList *tags, *l;
1525 GtkTextIter iter;
1526 gboolean hovering = FALSE(0);
1527
1528 priv = defbox->priv;
1529
1530 if (!priv->hand_cursor)
1531 {
1532 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1533 priv->hand_cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
1534 }
1535
1536 if (!priv->regular_cursor)
1537 {
1538 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1539 priv->regular_cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
1540 }
1541
1542 gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
1543
1544 tags = gtk_text_iter_get_tags (&iter);
1545 for (l = tags; l != NULL((void*)0); l = l->next)
1546 {
1547 GtkTextTag *tag = l->data;
1548 gchar *name;
1549
1550 g_object_get (G_OBJECT (tag)((((GObject*) (void *) ((tag))))), "name", &name, NULL((void*)0));
1551 if (name &&
1552 (strcmp (name, "link") == 0 ||
1553 strcmp (name, "visited-link") == 0))
1554 {
1555 hovering = TRUE(!(0));
1556 g_free (name);
1557
1558 break;
1559 }
1560
1561 g_free (name);
1562 }
1563
1564 if (hovering != defbox->priv->is_hovering)
1565 {
1566 defbox->priv->is_hovering = (hovering != FALSE(0));
1567
1568 if (defbox->priv->is_hovering)
1569 gdk_window_set_cursor (gtk_text_view_get_window (text_view,
1570 GTK_TEXT_WINDOW_TEXT),
1571 defbox->priv->hand_cursor);
1572 else
1573 gdk_window_set_cursor (gtk_text_view_get_window (text_view,
1574 GTK_TEXT_WINDOW_TEXT),
1575 defbox->priv->regular_cursor);
1576 }
1577
1578 if (tags)
1579 g_slist_free (tags);
1580}
1581
1582static gboolean
1583defbox_motion_notify_cb (GtkWidget *text_view,
1584 GdkEventMotion *event,
1585 GdictDefbox *defbox)
1586{
1587 gint bx, by;
1588
1589 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1590 GTK_TEXT_WINDOW_WIDGET,
1591 event->x, event->y,
1592 &bx, &by);
1593
1594 set_cursor_if_appropriate (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), bx, by);
1595
1596 return FALSE(0);
1597}
1598
1599static gboolean
1600defbox_visibility_notify_cb (GtkWidget *text_view,
1601 GdkEventVisibility *event,
1602 GdictDefbox *defbox)
1603{
1604 GdkDisplay *display;
1605 GdkSeat *seat;
1606 GdkDevice *pointer;
1607 gint wx, wy;
1608 gint bx, by;
1609
1610 display = gdk_window_get_display (event->window);
1611 seat = gdk_display_get_default_seat (display);
1612 pointer = gdk_seat_get_pointer (seat);
1613 gdk_window_get_device_position (gtk_widget_get_window (text_view), pointer, &wx, &wy, NULL((void*)0));
1614
1615 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1616 GTK_TEXT_WINDOW_WIDGET,
1617 wx, wy,
1618 &bx, &by);
1619
1620 set_cursor_if_appropriate (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), bx, by);
1621
1622 return FALSE(0);
1623}
1624
1625static GObject *
1626gdict_defbox_constructor (GType type,
1627 guint n_construct_properties,
1628 GObjectConstructParam *construct_params)
1629{
1630 GdictDefbox *defbox;
1631 GdictDefboxPrivate *priv;
1632 GObject *object;
1633 GtkWidget *sw;
1634
1635 object = G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->constructor (type,
1636 n_construct_properties,
1637 construct_params);
1638 defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
1639 priv = defbox->priv;
1640
1641 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
1642 gtk_widget_set_vexpand (sw, TRUE(!(0)));
1643 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) ((sw))))),
1644 GTK_POLICY_AUTOMATIC,
1645 GTK_POLICY_AUTOMATIC);
1646 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) ((sw))))),
1647 GTK_SHADOW_IN);
1648 gtk_box_pack_start (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), sw, TRUE(!(0)), TRUE(!(0)), 0);
1649 gtk_widget_show (sw);
1650
1651 priv->buffer = gtk_text_buffer_new (NULL((void*)0));
1652 gdict_defbox_init_tags (defbox);
1653
1654 priv->text_view = gtk_text_view_new_with_buffer (priv->buffer);
1655 gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))), FALSE(0));
1656 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))), 4);
1657 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) ((sw))))), priv->text_view);
1658 gtk_widget_show (priv->text_view);
1659
1660 priv->find_pane = create_find_pane (defbox);
1661 gtk_box_pack_end (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), priv->find_pane, FALSE(0), FALSE(0), 0);
1662
1663 /* stuff to make the link machinery work */
1664 g_signal_connect (priv->text_view, "event-after",g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
1665 G_CALLBACK (defbox_event_after_cb),g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
1666 defbox)g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
;
1667 g_signal_connect (priv->text_view, "motion-notify-event",g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
1668 G_CALLBACK (defbox_motion_notify_cb),g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
1669 defbox)g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
;
1670 g_signal_connect (priv->text_view, "visibility-notify-event",g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
1671 G_CALLBACK (defbox_visibility_notify_cb),g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
1672 defbox)g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
;
1673
1674 return object;
1675}
1676
1677/* we override the GtkWidget::show_all method since we have widgets
1678 * we don't want to show, such as the find pane
1679 */
1680static void
1681gdict_defbox_show_all (GtkWidget *widget)
1682{
1683 GdictDefbox *defbox = GDICT_DEFBOX (widget)((((GdictDefbox*) (void *) ((widget)))));
1684 GdictDefboxPrivate *priv = defbox->priv;
1685
1686 gtk_widget_show (widget);
1687
1688 if (priv->show_find)
1689 gtk_widget_show_all (priv->find_pane);
1690}
1691
1692static void
1693gdict_defbox_real_show_find (GdictDefbox *defbox)
1694{
1695 gtk_widget_show_all (defbox->priv->find_pane);
1696 defbox->priv->show_find = TRUE(!(0));
1697
1698 gtk_widget_grab_focus (defbox->priv->find_entry);
1699
1700 defbox->priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1701}
1702
1703static void
1704gdict_defbox_real_find_next (GdictDefbox *defbox)
1705{
1706 /* synthetize a "clicked" signal to the "next" button */
1707 gtk_button_clicked (GTK_BUTTON (defbox->priv->find_next)((((GtkButton*) (void *) ((defbox->priv->find_next))))));
1708}
1709
1710static void
1711gdict_defbox_real_find_previous (GdictDefbox *defbox)
1712{
1713 /* synthetize a "clicked" signal to the "prev" button */
1714 gtk_button_clicked (GTK_BUTTON (defbox->priv->find_prev)((((GtkButton*) (void *) ((defbox->priv->find_prev))))));
1715}
1716
1717static void
1718gdict_defbox_real_hide_find (GdictDefbox *defbox)
1719{
1720 gtk_widget_hide (defbox->priv->find_pane);
1721 defbox->priv->show_find = FALSE(0);
1722
1723 gtk_widget_grab_focus (defbox->priv->text_view);
1724
1725 if (defbox->priv->hide_timeout)
1726 {
1727 g_source_remove (defbox->priv->hide_timeout);
1728 defbox->priv->hide_timeout = 0;
1729 }
1730}
1731
1732static void
1733gdict_defbox_class_init (GdictDefboxClass *klass)
1734{
1735 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
1736 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass)((((GtkWidgetClass*) (void *) ((klass)))));
1737 GtkBindingSet *binding_set;
1738
1739 gobject_class->constructor = gdict_defbox_constructor;
1740 gobject_class->set_property = gdict_defbox_set_property;
1741 gobject_class->get_property = gdict_defbox_get_property;
1742 gobject_class->dispose = gdict_defbox_dispose;
1743 gobject_class->finalize = gdict_defbox_finalize;
1744
1745 widget_class->show_all = gdict_defbox_show_all;
1746
1747 /**
1748 * GdictDefbox:word:
1749 *
1750 * The word to look up.
1751 *
1752 * Since: 0.10
1753 */
1754 g_object_class_install_property (gobject_class,
1755 PROP_WORD,
1756 g_param_spec_string ("word",
1757 "Word",
1758 "The word to look up",
1759 NULL((void*)0),
1760 G_PARAM_READWRITE));
1761 /**
1762 * GdictDefbox:context:
1763 *
1764 * The #GdictContext object used to get the word definition.
1765 *
1766 * Since: 0.1
1767 */
1768 g_object_class_install_property (gobject_class,
1769 PROP_CONTEXT,
1770 g_param_spec_object ("context",
1771 "Context",
1772 "The GdictContext object used to get the word definition",
1773 GDICT_TYPE_CONTEXT(gdict_context_get_type ()),
1774 (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)));
1775 /**
1776 * GdictDefbox:database
1777 *
1778 * The database used by the #GdictDefbox bound to this object to get the word
1779 * definition.
1780 *
1781 * Since: 0.1
1782 */
1783 g_object_class_install_property (gobject_class,
1784 PROP_DATABASE,
1785 g_param_spec_string ("database",
1786 "Database",
1787 "The database used to query the GdictContext",
1788 GDICT_DEFAULT_DATABASE"*",
1789 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1790 /**
1791 * GdictDefbox:font-name
1792 *
1793 * The name of the font used by the #GdictDefbox to display the definitions.
1794 * use the same string you use for pango_font_description_from_string().
1795 *
1796 * Since: 0.3
1797 */
1798 g_object_class_install_property (gobject_class,
1799 PROP_FONT_NAME,
1800 g_param_spec_string ("font-name",
1801 "Font Name",
1802 "The font to be used by the defbox",
1803 GDICT_DEFAULT_FONT_NAME"Sans 10",
1804 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1805
1806 gdict_defbox_signals[SHOW_FIND] =
1807 g_signal_new ("show-find",
1808 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1809 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1810 G_STRUCT_OFFSET (GdictDefboxClass, show_find)((glong) __builtin_offsetof(GdictDefboxClass, show_find)),
1811 NULL((void*)0), NULL((void*)0),
1812 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1813 G_TYPE_NONE((GType) ((1) << (2))), 0);
1814 gdict_defbox_signals[FIND_PREVIOUS] =
1815 g_signal_new ("find-previous",
1816 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1817 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1818 G_STRUCT_OFFSET (GdictDefboxClass, find_previous)((glong) __builtin_offsetof(GdictDefboxClass, find_previous)),
1819 NULL((void*)0), NULL((void*)0),
1820 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1821 G_TYPE_NONE((GType) ((1) << (2))), 0);
1822 gdict_defbox_signals[FIND_NEXT] =
1823 g_signal_new ("find-next",
1824 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1825 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1826 G_STRUCT_OFFSET (GdictDefboxClass, find_next)((glong) __builtin_offsetof(GdictDefboxClass, find_next)),
1827 NULL((void*)0), NULL((void*)0),
1828 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1829 G_TYPE_NONE((GType) ((1) << (2))), 0);
1830 gdict_defbox_signals[HIDE_FIND] =
1831 g_signal_new ("hide-find",
1832 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1833 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1834 G_STRUCT_OFFSET (GdictDefboxClass, hide_find)((glong) __builtin_offsetof(GdictDefboxClass, hide_find)),
1835 NULL((void*)0), NULL((void*)0),
1836 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1837 G_TYPE_NONE((GType) ((1) << (2))), 0);
1838 gdict_defbox_signals[LINK_CLICKED] =
1839 g_signal_new ("link-clicked",
1840 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1841 G_SIGNAL_RUN_LAST,
1842 G_STRUCT_OFFSET (GdictDefboxClass, link_clicked)((glong) __builtin_offsetof(GdictDefboxClass, link_clicked)),
1843 NULL((void*)0), NULL((void*)0),
1844 gdict_marshal_VOID__STRINGg_cclosure_marshal_VOID__STRING,
1845 G_TYPE_NONE((GType) ((1) << (2))), 1,
1846 G_TYPE_STRING((GType) ((16) << (2))));
1847
1848 klass->show_find = gdict_defbox_real_show_find;
1849 klass->hide_find = gdict_defbox_real_hide_find;
1850 klass->find_next = gdict_defbox_real_find_next;
1851 klass->find_previous = gdict_defbox_real_find_previous;
1852
1853 binding_set = gtk_binding_set_by_class (klass);
1854 gtk_binding_entry_add_signal (binding_set,
1855 GDK_KEY_f0x066, GDK_CONTROL_MASK,
1856 "show-find",
1857 0);
1858 gtk_binding_entry_add_signal (binding_set,
1859 GDK_KEY_g0x067, GDK_CONTROL_MASK,
1860 "find-next",
1861 0);
1862 gtk_binding_entry_add_signal (binding_set,
1863 GDK_KEY_g0x067, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1864 "find-previous",
1865 0);
1866 gtk_binding_entry_add_signal (binding_set,
1867 GDK_KEY_Escape0xff1b, 0,
1868 "hide-find",
1869 0);
1870}
1871
1872static void
1873gdict_defbox_init (GdictDefbox *defbox)
1874{
1875 GdictDefboxPrivate *priv;
1876
1877 gtk_orientable_set_orientation (GTK_ORIENTABLE (defbox)((((GtkOrientable*) (void *) ((defbox))))), GTK_ORIENTATION_VERTICAL);
1878 gtk_box_set_spacing (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), 6);
1879
1880 priv = gdict_defbox_get_instance_private (defbox);
1881 defbox->priv = priv;
1882
1883 priv->context = NULL((void*)0);
1884 priv->database = g_strdup (GDICT_DEFAULT_DATABASE)g_strdup_inline ("*");
1885 priv->font_name = g_strdup (GDICT_DEFAULT_FONT_NAME)g_strdup_inline ("Sans 10");
1886 priv->word = NULL((void*)0);
1887
1888 priv->definitions = NULL((void*)0);
1889
1890 priv->busy_cursor = NULL((void*)0);
1891 priv->hand_cursor = NULL((void*)0);
1892 priv->regular_cursor = NULL((void*)0);
1893
1894 priv->show_find = FALSE(0);
1895 priv->is_searching = FALSE(0);
1896 priv->is_hovering = FALSE(0);
1897
1898 priv->hide_timeout = 0;
1899}
1900
1901/**
1902 * gdict_defbox_new:
1903 *
1904 * Creates a new #GdictDefbox widget. Use this widget to search for
1905 * a word using a #GdictContext, and to show the resulting definition(s).
1906 * You must set a #GdictContext for this widget using
1907 * gdict_defbox_set_context().
1908 *
1909 * Return value: a new #GdictDefbox widget.
1910 *
1911 * Since: 0.1
1912 */
1913GtkWidget *
1914gdict_defbox_new (void)
1915{
1916 return g_object_new (GDICT_TYPE_DEFBOX(gdict_defbox_get_type ()), NULL((void*)0));
1917}
1918
1919/**
1920 * gdict_defbox_new_with_context:
1921 * @context: a #GdictContext
1922 *
1923 * Creates a new #GdictDefbox widget. Use this widget to search for
1924 * a word using @context, and to show the resulting definition.
1925 *
1926 * Return value: a new #GdictDefbox widget.
1927 *
1928 * Since: 0.1
1929 */
1930GtkWidget *
1931gdict_defbox_new_with_context (GdictContext *context)
1932{
1933 g_return_val_if_fail (GDICT_IS_CONTEXT (context), NULL)do{ (void)0; }while (0);
1934
1935 return g_object_new (GDICT_TYPE_DEFBOX(gdict_defbox_get_type ()), "context", context, NULL((void*)0));
1936}
1937
1938/**
1939 * gdict_defbox_set_context:
1940 * @defbox: a #GdictDefbox
1941 * @context: a #GdictContext
1942 *
1943 * Sets @context as the #GdictContext to be used by @defbox in order
1944 * to retrieve the definitions of a word.
1945 *
1946 * Since: 0.1
1947 */
1948void
1949gdict_defbox_set_context (GdictDefbox *defbox,
1950 GdictContext *context)
1951{
1952 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
1953 g_return_if_fail (context == NULL || GDICT_IS_CONTEXT (context))do{ (void)0; }while (0);
1954
1955 g_object_set (defbox, "context", context, NULL((void*)0));
1956}
1957
1958/**
1959 * gdict_defbox_get_context:
1960 * @defbox: a #GdictDefbox
1961 *
1962 * Gets the #GdictContext used by @defbox.
1963 *
1964 * Return value: a #GdictContext.
1965 *
1966 * Since: 0.1
1967 */
1968GdictContext *
1969gdict_defbox_get_context (GdictDefbox *defbox)
1970{
1971 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
1972
1973 return defbox->priv->context;
1974}
1975
1976/**
1977 * gdict_defbox_set_database:
1978 * @defbox: a #GdictDefbox
1979 * @database: a database
1980 *
1981 * Sets @database as the database used by the #GdictContext bound to @defbox
1982 * to query for word definitions.
1983 *
1984 * Since: 0.1
1985 */
1986void
1987gdict_defbox_set_database (GdictDefbox *defbox,
1988 const gchar *database)
1989{
1990 GdictDefboxPrivate *priv;
1991
1992 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
1993
1994 priv = defbox->priv;
1995
1996 g_free (priv->database);
1997 priv->database = g_strdup (database)g_strdup_inline (database);
1998
1999 g_object_notify (G_OBJECT (defbox)((((GObject*) (void *) ((defbox))))), "database");
2000}
2001
2002/**
2003 * gdict_defbox_get_database:
2004 * @defbox: a #GdictDefbox
2005 *
2006 * Gets the database used by @defbox. See gdict_defbox_set_database().
2007 *
2008 * Return value: the name of a database. The return string is owned by
2009 * the #GdictDefbox widget and should not be modified or freed.
2010 *
2011 * Since: 0.1
2012 */
2013const gchar *
2014gdict_defbox_get_database (GdictDefbox *defbox)
2015{
2016 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2017
2018 return defbox->priv->database;
2019}
2020
2021/**
2022 * gdict_defbox_get_word:
2023 * @defbox: a #GdictDefbox
2024 *
2025 * Retrieves the word being looked up.
2026 *
2027 * Return value: the word looked up, or %NULL. The returned string is
2028 * owned by the #GdictDefbox widget and should never be modified or
2029 * freed.
2030 *
2031 * Since: 0.12
2032 */
2033const gchar *
2034gdict_defbox_get_word (GdictDefbox *defbox)
2035{
2036 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2037
2038 return defbox->priv->word;
2039}
2040
2041/**
2042 * gdict_defbox_set_show_find:
2043 * @defbox: a #GdictDefbox
2044 * @show_find: %TRUE to show the find pane
2045 *
2046 * Whether @defbox should show the find pane.
2047 *
2048 * Since: 0.1
2049 */
2050void
2051gdict_defbox_set_show_find (GdictDefbox *defbox,
2052 gboolean show_find)
2053{
2054 GdictDefboxPrivate *priv;
2055
2056 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2057
2058 priv = defbox->priv;
2059
2060 if (priv->show_find == show_find)
2061 return;
2062
2063 priv->show_find = (show_find != FALSE(0));
2064 if (priv->show_find)
2065 {
2066 gtk_widget_show_all (priv->find_pane);
2067 gtk_widget_grab_focus (priv->find_entry);
2068
2069 if (!priv->hide_timeout)
2070 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
2071 }
2072 else
2073 {
2074 gtk_widget_hide (priv->find_pane);
2075
2076 if (priv->hide_timeout)
2077 {
2078 g_source_remove (priv->hide_timeout);
2079 priv->hide_timeout = 0;
2080 }
2081 }
2082}
2083
2084/**
2085 * gdict_defbox_get_show_find:
2086 * @defbox: a #GdictDefbox
2087 *
2088 * Gets whether the find pane should be visible or not.
2089 *
2090 * Return value: %TRUE if the find pane is visible.
2091 *
2092 * Since: 0.1
2093 */
2094gboolean
2095gdict_defbox_get_show_find (GdictDefbox *defbox)
2096{
2097 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), FALSE)do{ (void)0; }while (0);
2098
2099 return (defbox->priv->show_find == TRUE(!(0)));
2100}
2101
2102static void
2103lookup_start_cb (GdictContext *context,
2104 gpointer user_data)
2105{
2106 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2107 GdictDefboxPrivate *priv = defbox->priv;
2108 GdkWindow *window;
2109
2110 priv->is_searching = TRUE(!(0));
2111
2112 if (!priv->busy_cursor)
2113 {
2114 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
2115 priv->busy_cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
2116 }
2117
2118 window = gtk_text_view_get_window (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2119 GTK_TEXT_WINDOW_WIDGET);
2120
2121 gdk_window_set_cursor (window, priv->busy_cursor);
2122}
2123
2124static void
2125lookup_end_cb (GdictContext *context,
2126 gpointer user_data)
2127{
2128 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2129 GdictDefboxPrivate *priv = defbox->priv;
2130 GtkTextBuffer *buffer;
2131 GtkTextIter start;
2132 GdkWindow *window;
2133
2134 /* explicitely move the cursor to the beginning */
2135 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2136 gtk_text_buffer_get_start_iter (buffer, &start);
2137 gtk_text_buffer_place_cursor (buffer, &start);
2138
2139 window = gtk_text_view_get_window (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2140 GTK_TEXT_WINDOW_WIDGET);
2141
2142 gdk_window_set_cursor (window, NULL((void*)0));
2143
2144 priv->is_searching = FALSE(0);
2145}
2146
2147static void
2148gdict_defbox_insert_word (GdictDefbox *defbox,
2149 GtkTextIter *iter,
2150 const gchar *word)
2151{
2152 GdictDefboxPrivate *priv;
2153 gchar *text;
2154
2155 if (!word)
2156 return;
2157
2158 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2159 priv = defbox->priv;
2160
2161 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2162
2163 text = g_strdup_printf ("%s\n", word);
2164 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2165 iter,
2166 text, strlen (text),
2167 "big", "bold", "query-title",
2168 NULL((void*)0));
2169 g_free (text);
2170}
2171
2172/* escape a link string; links are expressed as "{...}".
2173 * the link with the '{}' removed is stored inside link_str, while
2174 * the returned value is a pointer to what follows the trailing '}'.
2175 * link_str is allocated and should be freed.
2176 */
2177static const gchar *
2178escape_link (const gchar *str,
2179 gchar **link_str)
2180{
2181 gsize str_len;
2182 GString *link_buf;
2183 const gchar *p;
2184
2185 str_len = strlen (str);
2186 link_buf = g_string_sized_new (str_len - 2);
2187
2188 for (p = str + 1; *p != '}'; p++)
2189 {
2190 link_buf = g_string_append_c (link_buf, *p)g_string_append_c_inline (link_buf, *p);
2191 }
2192
2193 if (link_str)
2194 *link_str = g_string_free (link_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((link_buf
), ((0))) : g_string_free_and_steal (link_buf)) : (g_string_free
) ((link_buf), ((0))))
;
2195
2196 p++;
2197
2198 return p;
2199}
2200
2201static const gchar *
2202escape_phonethic (const gchar *str,
2203 gchar **phon_str)
2204{
2205 gsize str_len;
2206 GString *phon_buf;
2207 const gchar *p;
2208
2209 str_len = strlen (str);
2210 phon_buf = g_string_sized_new (str_len - 2);
2211
2212 for (p = str + 1; *p != '\\'; p++)
2213 {
2214 phon_buf = g_string_append_c (phon_buf, *p)g_string_append_c_inline (phon_buf, *p);
2215 }
2216
2217 if (phon_str)
2218 *phon_str = g_string_free (phon_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((phon_buf
), ((0))) : g_string_free_and_steal (phon_buf)) : (g_string_free
) ((phon_buf), ((0))))
;
2219
2220 p++;
2221
2222 return p;
2223}
2224
2225static void
2226gdict_defbox_insert_body (GdictDefbox *defbox,
2227 GtkTextIter *iter,
2228 const gchar *body)
2229{
2230 GdictDefboxPrivate *priv;
2231 gchar **words;
2232 gint len, i;
2233 GtkTextIter end_iter;
2234
2235 if (!body)
2236 return;
2237
2238 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2239 priv = defbox->priv;
2240
2241 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2242
2243 words = g_strsplit (body, " ", -1);
2244 len = g_strv_length (words);
2245 end_iter = *iter;
2246
2247 for (i = 0; i < len; i++)
2248 {
2249 gchar *w = words[i];
2250 gint w_len = strlen (w);
2251 gchar *begin, *end;
2252
2253 if (w_len == 0)
2254 continue;
2255
2256 begin = g_utf8_offset_to_pointer (w, 0);
2257
2258 if (*begin == '{')
2259 {
2260 end = g_utf8_strrchr (w, -1, '}');
2261
2262 /* see this is a self contained link */
2263 if (end && *end == '}')
2264 {
2265 const gchar *rest;
2266 gchar *link_str;
2267
2268 rest = escape_link (w, &link_str);
2269
2270 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2271 &end_iter,
2272 link_str, -1,
2273 "link",
2274 NULL((void*)0));
2275
2276 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2277
2278 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2279 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2280
2281 g_free (link_str);
2282
2283 continue;
2284 }
2285 else
2286 {
2287 /* uh-oh: the link ends in another word */
2288 GString *buf;
2289 gchar *next;
2290 gint cur = i;
2291
2292 buf = g_string_new (NULL((void*)0));
2293 next = words[cur++];
2294
2295 while (next && (end = g_utf8_strrchr (next, -1, '}')) == NULL((void*)0))
2296 {
2297 buf = g_string_append (buf, next)(__builtin_constant_p (next) ? __extension__ ({ const char * const
__val = (next); g_string_append_len_inline (buf, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (buf, next, (gssize) -
1))
;
2298 buf = g_string_append_c (buf, ' ')g_string_append_c_inline (buf, ' ');
2299
2300 next = words[cur++];
2301 }
2302
2303 buf = g_string_append (buf, next)(__builtin_constant_p (next) ? __extension__ ({ const char * const
__val = (next); g_string_append_len_inline (buf, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (buf, next, (gssize) -
1))
;
2304
2305 next = g_string_free (buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((buf)
, ((0))) : g_string_free_and_steal (buf)) : (g_string_free) (
(buf), ((0))))
;
2306
2307 if (end && *end == '}')
2308 {
2309 const gchar *rest;
2310 gchar *link_str;
2311
2312 rest = escape_link (next, &link_str);
2313
2314 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2315 &end_iter,
2316 link_str, -1,
2317 "link",
2318 NULL((void*)0));
2319
2320 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2321 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2322
2323 g_free (link_str);
2324 }
2325
2326 g_free (next);
2327 i = cur;
2328
2329 continue;
2330 }
2331 }
2332 else if (*begin == '\\')
2333 {
2334 end = g_utf8_strrchr (w, -1, '\\');
2335
2336 if (end && *end == '\\')
2337 {
2338 const gchar *rest;
2339 gchar *phon;
2340
2341 rest = escape_phonethic (w, &phon);
2342
2343 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2344 &end_iter,
2345 phon, -1,
2346 "italic", "phonetic",
2347 NULL((void*)0));
2348
2349 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2350
2351 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2352 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", -1);
2353
2354 g_free (phon);
2355
2356 continue;
2357 }
2358 }
2359
2360 gtk_text_buffer_insert (priv->buffer, &end_iter, w, w_len);
2361
2362 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2363 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2364 }
2365
2366 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2367 gtk_text_buffer_insert (priv->buffer, &end_iter, "\n", 1);
2368
2369 *iter = end_iter;
2370
2371 g_strfreev (words);
2372}
2373
2374static void
2375gdict_defbox_insert_from (GdictDefbox *defbox,
2376 GtkTextIter *iter,
2377 const gchar *database)
2378{
2379 GdictDefboxPrivate *priv;
2380 gchar *text;
2381
2382 if (!database)
2383 return;
2384
2385 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2386 priv = defbox->priv;
2387
2388 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2389
2390 text = g_strdup_printf ("\t-- From %s\n\n", database);
2391 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2392 iter,
2393 text, strlen (text),
2394 "small", "query-from",
2395 NULL((void*)0));
2396 g_free (text);
2397}
2398
2399static void
2400gdict_defbox_insert_error (GdictDefbox *defbox,
2401 GtkTextIter *iter,
2402 const gchar *title,
2403 const gchar *message)
2404{
2405 GdictDefboxPrivate *priv;
2406 GtkTextMark *mark;
2407 GtkTextIter cur_iter;
2408
2409 if (!title)
2410 return;
2411
2412 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2413 priv = defbox->priv;
2414
2415 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2416
2417 mark = gtk_text_buffer_create_mark (priv->buffer, "block-cursor", iter, FALSE(0));
2418 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2419
2420 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2421 &cur_iter,
2422 title, strlen (title),
2423 "error-title", "big", "bold",
2424 NULL((void*)0));
2425 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2426
2427 gtk_text_buffer_insert (priv->buffer, &cur_iter, "\n\n", -1);
2428 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2429
2430 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2431 &cur_iter,
2432 message, strlen (message),
2433 "error-message",
2434 NULL((void*)0));
2435}
2436
2437static void
2438definition_found_cb (GdictContext *context,
2439 GdictDefinition *definition,
2440 gpointer user_data)
2441{
2442 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2443 GdictDefboxPrivate *priv = defbox->priv;
2444 GtkTextIter iter;
2445 Definition *def;
2446
2447 /* insert the word if this is the first definition */
2448 if (!priv->definitions)
2449 {
2450 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2451 gdict_defbox_insert_word (defbox, &iter,
2452 gdict_definition_get_word (definition));
2453 }
2454
2455 def = definition_new ();
2456
2457 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
2458 def->begin = gtk_text_iter_get_offset (&iter);
2459 gdict_defbox_insert_body (defbox, &iter, gdict_definition_get_text (definition));
2460
2461 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
2462 gdict_defbox_insert_from (defbox, &iter, gdict_definition_get_database (definition));
2463
2464 def->definition = gdict_definition_ref (definition);
2465
2466 priv->definitions = g_slist_append (priv->definitions, def);
2467}
2468
2469static void
2470error_cb (GdictContext *context,
2471 const GError *error,
2472 gpointer user_data)
2473{
2474 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2475 GdictDefboxPrivate *priv = defbox->priv;
2476 GtkTextIter iter;
2477
2478 if (!error)
2479 return;
2480
2481 gdict_defbox_clear (defbox);
2482
2483 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2484 gdict_defbox_insert_error (defbox, &iter,
2485 _("Error while looking up definition")((char *) g_dgettext ("mate-utils", "Error while looking up definition"
))
,
2486 error->message);
2487
2488 g_free (priv->word);
2489 priv->word = NULL((void*)0);
2490
2491 defbox->priv->is_searching = FALSE(0);
2492}
2493
2494/**
2495 * gdict_defbox_lookup:
2496 * @defbox: a #GdictDefbox
2497 * @word: the word to look up
2498 *
2499 * Searches @word inside the dictionary sources using the #GdictContext
2500 * provided when creating @defbox or set using gdict_defbox_set_context().
2501 *
2502 * Since: 0.1
2503 */
2504void
2505gdict_defbox_lookup (GdictDefbox *defbox,
2506 const gchar *word)
2507{
2508 GdictDefboxPrivate *priv;
2509 GError *define_error;
2510
2511 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2512
2513 priv = defbox->priv;
2514
2515 if (!priv->context)
2516 {
2517 g_warning ("Attempting to look up `%s', but no GdictContext "
2518 "has been set. Use gdict_defbox_set_context() "
2519 "before invoking gdict_defbox_lookup().",
2520 word);
2521 return;
2522 }
2523
2524 if (priv->is_searching)
2525 {
2526 _gdict_show_error_dialog (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))),
2527 _("Another search is in progress")((char *) g_dgettext ("mate-utils", "Another search is in progress"
))
,
2528 _("Please wait until the current search ends.")((char *) g_dgettext ("mate-utils", "Please wait until the current search ends."
))
);
2529
2530 return;
2531 }
2532
2533 gdict_defbox_clear (defbox);
2534
2535 if (!priv->start_id)
2536 {
2537 priv->start_id = g_signal_connect (priv->context, "lookup-start",g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2538 G_CALLBACK (lookup_start_cb),g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2539 defbox)g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
2540 priv->define_id = g_signal_connect (priv->context, "definition-found",g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
2541 G_CALLBACK (definition_found_cb),g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
2542 defbox)g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
;
2543 priv->end_id = g_signal_connect (priv->context, "lookup-end",g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2544 G_CALLBACK (lookup_end_cb),g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2545 defbox)g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
2546 }
2547
2548 if (!priv->error_id)
2549 priv->error_id = g_signal_connect (priv->context, "error",g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
2550 G_CALLBACK (error_cb),g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
2551 defbox)g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
;
2552
2553 g_free (priv->word);
2554 priv->word = g_strdup (word)g_strdup_inline (word);
2555 g_object_notify (G_OBJECT (defbox)((((GObject*) (void *) ((defbox))))), "word");
2556
2557 define_error = NULL((void*)0);
2558 gdict_context_define_word (priv->context,
2559 priv->database,
2560 word,
2561 &define_error);
2562 if (define_error)
2563 {
2564 GtkTextIter iter;
2565
2566 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2567 gdict_defbox_insert_error (defbox, &iter,
2568 _("Error while retrieving the definition")((char *) g_dgettext ("mate-utils", "Error while retrieving the definition"
))
,
2569 define_error->message);
2570
2571 g_error_free (define_error);
2572 }
2573}
2574
2575/**
2576 * gdict_defbox_clear:
2577 * @defbox: a @GdictDefbox
2578 *
2579 * Clears the buffer of @defbox
2580 *
2581 * Since: 0.1
2582 */
2583void
2584gdict_defbox_clear (GdictDefbox *defbox)
2585{
2586 GdictDefboxPrivate *priv;
2587 GtkTextIter start, end;
2588
2589 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2590
2591 priv = defbox->priv;
2592
2593 /* destroy previously found definitions */
2594 if (priv->definitions)
2595 {
2596 g_slist_free_full (priv->definitions, (GDestroyNotify) definition_free);
2597 priv->definitions = NULL((void*)0);
2598 }
2599
2600 gtk_text_buffer_get_bounds (priv->buffer, &start, &end);
2601 gtk_text_buffer_delete (priv->buffer, &start, &end);
2602}
2603
2604/**
2605 * gdict_defbox_find_next:
2606 * @defbox: a #GdictDefbox
2607 *
2608 * Emits the "find-next" signal.
2609 *
2610 * Since: 0.1
2611 */
2612void
2613gdict_defbox_find_next (GdictDefbox *defbox)
2614{
2615 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2616
2617 g_signal_emit (defbox, gdict_defbox_signals[FIND_NEXT], 0);
2618}
2619
2620/**
2621 * gdict_defbox_find_previous:
2622 * @defbox: a #GdictDefbox
2623 *
2624 * Emits the "find-previous" signal.
2625 *
2626 * Since: 0.1
2627 */
2628void
2629gdict_defbox_find_previous (GdictDefbox *defbox)
2630{
2631 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2632
2633 g_signal_emit (defbox, gdict_defbox_signals[FIND_PREVIOUS], 0);
2634}
2635
2636/**
2637 * gdict_defbox_select_all:
2638 * @defbox: a #GdictDefbox
2639 *
2640 * Selects all the text displayed by @defbox
2641 *
2642 * Since: 0.1
2643 */
2644void
2645gdict_defbox_select_all (GdictDefbox *defbox)
2646{
2647 GdictDefboxPrivate *priv;
2648 GtkTextBuffer *buffer;
2649 GtkTextIter start, end;
2650
2651 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2652
2653 priv = defbox->priv;
2654 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2655
2656 gtk_text_buffer_get_bounds (buffer, &start, &end);
2657 gtk_text_buffer_select_range (buffer, &start, &end);
2658}
2659
2660/**
2661 * gdict_defbox_copy_to_clipboard:
2662 * @defbox: a #GdictDefbox
2663 * @clipboard: a #GtkClipboard
2664 *
2665 * Copies the selected text inside @defbox into @clipboard.
2666 *
2667 * Since: 0.1
2668 */
2669void
2670gdict_defbox_copy_to_clipboard (GdictDefbox *defbox,
2671 GtkClipboard *clipboard)
2672{
2673 GdictDefboxPrivate *priv;
2674 GtkTextBuffer *buffer;
2675
2676 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2677 g_return_if_fail (GTK_IS_CLIPBOARD (clipboard))do{ (void)0; }while (0);
2678
2679 priv = defbox->priv;
2680 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2681
2682 gtk_text_buffer_copy_clipboard (buffer, clipboard);
2683}
2684
2685/**
2686 * gdict_defbox_count_definitions:
2687 * @defbox: a #GdictDefbox
2688 *
2689 * Gets the number of definitions displayed by @defbox
2690 *
2691 * Return value: the number of definitions.
2692 *
2693 * Since: 0.1
2694 */
2695gint
2696gdict_defbox_count_definitions (GdictDefbox *defbox)
2697{
2698 GdictDefboxPrivate *priv;
2699
2700 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), -1)do{ (void)0; }while (0);
2701
2702 priv = defbox->priv;
2703 if (!priv->definitions)
2704 return -1;
2705
2706 return g_slist_length (priv->definitions);
2707}
2708
2709/**
2710 * gdict_defbox_jump_to_definition:
2711 * @defbox: a #GdictDefbox
2712 * @number: the definition to jump to
2713 *
2714 * Scrolls to the definition identified by @number. If @number is -1,
2715 * jumps to the last definition.
2716 *
2717 * Since: 0.1
2718 */
2719void
2720gdict_defbox_jump_to_definition (GdictDefbox *defbox,
2721 gint number)
2722{
2723 GdictDefboxPrivate *priv;
2724 gint count;
2725 Definition *def;
2726 GtkTextBuffer *buffer;
2727 GtkTextIter def_start;
2728
2729 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2730
2731 count = gdict_defbox_count_definitions (defbox) - 1;
2732 if (count == -1)
2733 return;
2734
2735 if ((number == -1) || (number > count))
2736 number = count;
2737
2738 priv = defbox->priv;
2739 def = (Definition *) g_slist_nth_data (priv->definitions, number);
2740 if (!def)
2741 return;
2742
2743 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2744 gtk_text_buffer_get_iter_at_offset (buffer, &def_start, def->begin);
2745 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2746 &def_start,
2747 0.0,
2748 TRUE(!(0)),
2749 0.0, 0.0);
2750}
2751
2752/**
2753 * gdict_defbox_get_text:
2754 * @defbox: a #GdictDefbox
2755 * @length: return location for the text length or %NULL
2756 *
2757 * Gets the full contents of @defbox.
2758 *
2759 * Return value: a newly allocated string containing the text displayed by
2760 * @defbox.
2761 *
2762 * Since: 0.1
2763 */
2764gchar *
2765gdict_defbox_get_text (GdictDefbox *defbox,
2766 gsize *length)
2767{
2768 GdictDefboxPrivate *priv;
2769 GtkTextBuffer *buffer;
2770 GtkTextIter start, end;
2771 gchar *retval;
2772
2773 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2774
2775 priv = defbox->priv;
2776 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2777
2778 gtk_text_buffer_get_bounds (buffer, &start, &end);
2779
2780 retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
2781
2782 if (length)
2783 *length = strlen (retval);
2784
2785 return retval;
2786}
2787
2788/**
2789 * gdict_defbox_set_font_name:
2790 * @defbox: a #GdictDefbox
2791 * @font_name: a font description, or %NULL
2792 *
2793 * Sets @font_name as the font for @defbox. It calls internally
2794 * pango_font_description_from_string() and gtk_widget_modify_font().
2795 *
2796 * Passing %NULL for @font_name will reset any previously set font.
2797 *
2798 * Since: 0.3.0
2799 */
2800void
2801gdict_defbox_set_font_name (GdictDefbox *defbox,
2802 const gchar *font_name)
2803{
2804 GdictDefboxPrivate *priv;
2805 PangoFontDescription *font_desc;
2806
2807 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2808
2809 priv = defbox->priv;
2810
2811 if (font_name)
2812 {
2813 font_desc = pango_font_description_from_string (font_name);
2814 g_return_if_fail (font_desc != NULL)do{ (void)0; }while (0);
2815 }
2816 else
2817 font_desc = NULL((void*)0);
2818
2819 gtk_widget_override_font (priv->text_view, font_desc);
2820
2821 if (font_desc)
2822 pango_font_description_free (font_desc);
2823
2824 g_free (priv->font_name);
2825 priv->font_name = g_strdup (font_name)g_strdup_inline (font_name);
2826}
2827
2828/**
2829 * gdict_defbox_get_font_name:
2830 * @defbox: a #GdictDefbox
2831 *
2832 * Retrieves the font currently used by @defbox.
2833 *
2834 * Return value: a font name. The returned string is owned by @defbox and
2835 * should not be modified or freed.
2836 *
2837 * Since: 0.3
2838 */
2839const gchar *
2840gdict_defbox_get_font_name (GdictDefbox *defbox)
2841{
2842 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2843
2844 return defbox->priv->font_name;
2845}
2846
2847/**
2848 * gdict_defbox_get_selected_word:
2849 * @defbox: a #GdictDefbox
2850 *
2851 * Retrieves the selected word from the defbox widget
2852 *
2853 * Return value: a newly allocated string containing the selected
2854 * word. Use g_free() when done using it.
2855 *
2856 * Since: 0.12
2857 */
2858gchar *
2859gdict_defbox_get_selected_word (GdictDefbox *defbox)
2860{
2861 GdictDefboxPrivate *priv;
2862 GtkTextBuffer *buffer;
2863
2864 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2865
2866 priv = defbox->priv;
2867 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2868
2869 if (!gtk_text_buffer_get_has_selection (buffer))
2870 return NULL((void*)0);
2871 else
2872 {
2873 GtkTextIter start, end;
2874 gchar *retval;
2875
2876 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
2877 retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
2878
2879 return retval;
2880 }
2881}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bcdee0.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bcdee0.html new file mode 100644 index 00000000..2c5c81df --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-bcdee0.html @@ -0,0 +1,2893 @@ + + + +gdict-client-context.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

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

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

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

Bug Summary

+ + + + +
File:gsearchtool/mate-submodules/libegg/eggsmclient-xsmp.c
Warning:line 1232, column 18
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name eggsmclient-xsmp.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/gsearchtool/mate-submodules/libegg -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D EGG_SM_CLIENT_BACKEND_XSMP -D G_LOG_DOMAIN="EggSMClient" -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D PIC -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/gsearchtool/mate-submodules/libegg -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c eggsmclient-xsmp.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/*
2 * Copyright (C) 2007 Novell, Inc.
3 *
4 * Inspired by various other pieces of code including GsmClient (C)
5 * 2001 Havoc Pennington, MateClient (C) 1998 Carsten Schaar, and twm
6 * session code (C) 1998 The Open Group.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25
26#include "eggsmclient.h"
27#include "eggsmclient-private.h"
28
29#include "eggdesktopfile.h"
30
31#include <errno(*__errno_location ()).h>
32#include <fcntl.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <X11/SM/SMlib.h>
37
38#include <gtk/gtk.h>
39#include <gdk/gdk.h>
40
41#if defined(GDK_WINDOWING_X11) || defined(HAVE_X11)
42#include <gdk/gdkx.h>
43#endif
44
45#define EGG_TYPE_SM_CLIENT_XSMP(egg_sm_client_xsmp_get_type ()) (egg_sm_client_xsmp_get_type ())
46#define EGG_SM_CLIENT_XSMP(obj)((((EggSMClientXSMP*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((egg_sm_client_xsmp_get_type ()))))))
(G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP)(((EggSMClientXSMP*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((egg_sm_client_xsmp_get_type ())))))
)
47#define EGG_SM_CLIENT_XSMP_CLASS(klass)((((EggSMClientXSMPClass*) (void *) g_type_check_class_cast (
(GTypeClass*) ((klass)), ((egg_sm_client_xsmp_get_type ()))))
))
(G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)(((EggSMClientXSMPClass*) (void *) g_type_check_class_cast ((
GTypeClass*) ((klass)), ((egg_sm_client_xsmp_get_type ())))))
)
48#define EGG_IS_SM_CLIENT_XSMP(obj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
49#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; }))))
(G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((egg_sm_client_xsmp_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; })))
)
50#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj)((((EggSMClientXSMPClass*) (((GTypeInstance*) ((obj)))->g_class
))))
(G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)(((EggSMClientXSMPClass*) (((GTypeInstance*) ((obj)))->g_class
)))
)
51
52typedef struct _EggSMClientXSMP EggSMClientXSMP;
53typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass;
54
55/* These mostly correspond to the similarly-named states in section
56 * 9.1 of the XSMP spec. Some of the states there aren't represented
57 * here, because we don't need them. SHUTDOWN_CANCELLED is slightly
58 * different from the spec; we use it when the client is IDLE after a
59 * ShutdownCancelled message, but the application is still interacting
60 * and doesn't know the shutdown has been cancelled yet.
61 */
62typedef enum
63{
64 XSMP_STATE_IDLE,
65 XSMP_STATE_SAVE_YOURSELF,
66 XSMP_STATE_INTERACT_REQUEST,
67 XSMP_STATE_INTERACT,
68 XSMP_STATE_SAVE_YOURSELF_DONE,
69 XSMP_STATE_SHUTDOWN_CANCELLED,
70 XSMP_STATE_CONNECTION_CLOSED
71} EggSMClientXSMPState;
72
73static const char *state_names[] =
74{
75 "idle",
76 "save-yourself",
77 "interact-request",
78 "interact",
79 "save-yourself-done",
80 "shutdown-cancelled",
81 "connection-closed"
82};
83
84#define EGG_SM_CLIENT_XSMP_STATE(xsmp)(state_names[(xsmp)->state]) (state_names[(xsmp)->state])
85
86struct _EggSMClientXSMP
87{
88 EggSMClient parent;
89
90 SmcConn connection;
91 char *client_id;
92
93 EggSMClientXSMPState state;
94 char **restart_command;
95 gboolean set_restart_command;
96 int restart_style;
97 char **discard_command;
98 gboolean set_discard_command;
99
100 guint idle;
101
102 /* Current SaveYourself state */
103 guint expecting_initial_save_yourself : 1;
104 guint need_save_state : 1;
105 guint need_quit_requested : 1;
106 guint interact_errors : 1;
107 guint shutting_down : 1;
108
109 /* Todo list */
110 guint waiting_to_set_initial_properties : 1;
111 guint waiting_to_emit_quit : 1;
112 guint waiting_to_emit_quit_cancelled : 1;
113 guint waiting_to_save_myself : 1;
114
115};
116
117struct _EggSMClientXSMPClass
118{
119 EggSMClientClass parent_class;
120
121};
122
123static void sm_client_xsmp_startup (EggSMClient *client,
124 const char *client_id);
125static void sm_client_xsmp_set_restart_command (EggSMClient *client,
126 int argc,
127 const char **argv);
128static void sm_client_xsmp_set_discard_command (EggSMClient *client,
129 int argc,
130 const char **argv);
131static void sm_client_xsmp_will_quit (EggSMClient *client,
132 gboolean will_quit);
133static gboolean sm_client_xsmp_end_session (EggSMClient *client,
134 EggSMClientEndStyle style,
135 gboolean request_confirmation);
136
137static void xsmp_save_yourself (SmcConn smc_conn,
138 SmPointer client_data,
139 int save_style,
140 Boolint shutdown,
141 int interact_style,
142 Boolint fast);
143static void xsmp_die (SmcConn smc_conn,
144 SmPointer client_data);
145static void xsmp_save_complete (SmcConn smc_conn,
146 SmPointer client_data);
147static void xsmp_shutdown_cancelled (SmcConn smc_conn,
148 SmPointer client_data);
149static void xsmp_interact (SmcConn smc_conn,
150 SmPointer client_data);
151
152static SmProp *array_prop (const char *name,
153 ...);
154static SmProp *ptrarray_prop (const char *name,
155 GPtrArray *values);
156static SmProp *string_prop (const char *name,
157 const char *value);
158static SmProp *card8_prop (const char *name,
159 unsigned char value);
160
161static void set_properties (EggSMClientXSMP *xsmp, ...);
162static void delete_properties (EggSMClientXSMP *xsmp, ...);
163
164static GPtrArray *generate_command (char **restart_command,
165 const char *client_id,
166 const char *state_file);
167
168static void save_state (EggSMClientXSMP *xsmp);
169static void do_save_yourself (EggSMClientXSMP *xsmp);
170static void update_pending_events (EggSMClientXSMP *xsmp);
171
172static void ice_init (void);
173static gboolean process_ice_messages (IceConn ice_conn);
174static void smc_error_handler (SmcConn smc_conn,
175 Boolint swap,
176 int offending_minor_opcode,
177 unsigned long offending_sequence,
178 int error_class,
179 int severity,
180 SmPointer values);
181
182G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT)static void egg_sm_client_xsmp_init (EggSMClientXSMP *self); static
void egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass
); static GType egg_sm_client_xsmp_get_type_once (void); static
gpointer egg_sm_client_xsmp_parent_class = ((void*)0); static
gint EggSMClientXSMP_private_offset; static void egg_sm_client_xsmp_class_intern_init
(gpointer klass) { egg_sm_client_xsmp_parent_class = g_type_class_peek_parent
(klass); if (EggSMClientXSMP_private_offset != 0) g_type_class_adjust_private_offset
(klass, &EggSMClientXSMP_private_offset); egg_sm_client_xsmp_class_init
((EggSMClientXSMPClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer egg_sm_client_xsmp_get_instance_private
(EggSMClientXSMP *self) { return (((gpointer) ((guint8*) (self
) + (glong) (EggSMClientXSMP_private_offset)))); } GType egg_sm_client_xsmp_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 = egg_sm_client_xsmp_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 egg_sm_client_xsmp_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((egg_sm_client_get_type ()), g_intern_static_string ("EggSMClientXSMP"
), sizeof (EggSMClientXSMPClass), (GClassInitFunc)(void (*)(void
)) egg_sm_client_xsmp_class_intern_init, sizeof (EggSMClientXSMP
), (GInstanceInitFunc)(void (*)(void)) egg_sm_client_xsmp_init
, (GTypeFlags) 0); { {{};} } return g_define_type_id; }
183
184static void
185egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp)
186{
187 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
188 xsmp->connection = NULL((void*)0);
189 xsmp->restart_style = SmRestartIfRunning0;
190}
191
192static void
193egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
194{
195 EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
196
197 sm_client_class->startup = sm_client_xsmp_startup;
198 sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command;
199 sm_client_class->set_discard_command = sm_client_xsmp_set_discard_command;
200 sm_client_class->will_quit = sm_client_xsmp_will_quit;
201 sm_client_class->end_session = sm_client_xsmp_end_session;
202}
203
204EggSMClient *
205egg_sm_client_xsmp_new (void)
206{
207 if (!g_getenv ("SESSION_MANAGER"))
208 return NULL((void*)0);
209
210 return g_object_new (EGG_TYPE_SM_CLIENT_XSMP(egg_sm_client_xsmp_get_type ()), NULL((void*)0));
211}
212
213static gboolean
214sm_client_xsmp_set_initial_properties (gpointer user_data)
215{
216 EggSMClientXSMP *xsmp = user_data;
217 EggDesktopFile *desktop_file;
218 GPtrArray *clone, *restart;
219 char pid_str[64];
220
221 if (xsmp->idle)
222 {
223 g_source_remove (xsmp->idle);
224 xsmp->idle = 0;
225 }
226 xsmp->waiting_to_set_initial_properties = FALSE(0);
227
228 if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART)
229 xsmp->restart_style = SmRestartNever3;
230
231 /* Parse info out of desktop file */
232 desktop_file = egg_get_desktop_file ();
233 if (desktop_file)
234 {
235 GError *err = NULL((void*)0);
236 char **argv;
237 int argc;
238
239 if (xsmp->restart_style == SmRestartIfRunning0)
240 {
241 if (egg_desktop_file_get_boolean (desktop_file,
242 "X-MATE-AutoRestart", NULL((void*)0)))
243 xsmp->restart_style = SmRestartImmediately2;
244 }
245
246 if (!xsmp->set_restart_command)
247 {
248 char *cmdline;
249
250 cmdline = egg_desktop_file_parse_exec (desktop_file, NULL((void*)0), &err);
251 if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err))
252 {
253 egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp),
254 argc, (const char **)argv);
255 g_strfreev (argv);
256 }
257 else
258 {
259 g_warning ("Could not parse Exec line in desktop file: %s",
260 err->message);
261 g_error_free (err);
262 }
263 g_free (cmdline);
264 }
265 }
266
267 if (!xsmp->set_restart_command)
268 xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1);
269
270 clone = generate_command (xsmp->restart_command, NULL((void*)0), NULL((void*)0));
271 restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL((void*)0));
272
273 g_debug ("Setting initial properties");
274
275 /* Program, CloneCommand, RestartCommand, and UserID are required.
276 * ProcessID isn't required, but the SM may be able to do something
277 * useful with it.
278 */
279 g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ());
280 set_properties (xsmp,
281 string_prop (SmProgram"Program", g_get_prgname ()),
282 ptrarray_prop (SmCloneCommand"CloneCommand", clone),
283 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
284 string_prop (SmUserID"UserID", g_get_user_name ()),
285 string_prop (SmProcessID"ProcessID", pid_str),
286 card8_prop (SmRestartStyleHint"RestartStyleHint", xsmp->restart_style),
287 NULL((void*)0));
288 g_ptr_array_free (clone, TRUE(!(0)));
289 g_ptr_array_free (restart, TRUE(!(0)));
290
291 if (desktop_file)
292 {
293 set_properties (xsmp,
294 string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)),
295 NULL((void*)0));
296 }
297
298 update_pending_events (xsmp);
299 return FALSE(0);
300}
301
302/* This gets called from two different places: xsmp_die() (when the
303 * server asks us to disconnect) and process_ice_messages() (when the
304 * server disconnects unexpectedly).
305 */
306static void
307sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp)
308{
309 SmcConn connection;
310
311 if (!xsmp->connection)
312 return;
313
314 g_debug ("Disconnecting");
315
316 connection = xsmp->connection;
317 xsmp->connection = NULL((void*)0);
318 SmcCloseConnection (connection, 0, NULL((void*)0));
319 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
320
321 xsmp->waiting_to_save_myself = FALSE(0);
322 update_pending_events (xsmp);
323}
324
325static void
326sm_client_xsmp_startup (EggSMClient *client,
327 const char *client_id)
328{
329 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
330 SmcCallbacks callbacks;
331 char *ret_client_id;
332 char error_string_ret[256];
333
334 xsmp->client_id = g_strdup (client_id)g_strdup_inline (client_id);
335
336 ice_init ();
337 SmcSetErrorHandler (smc_error_handler);
338
339 callbacks.save_yourself.callback = xsmp_save_yourself;
340 callbacks.die.callback = xsmp_die;
341 callbacks.save_complete.callback = xsmp_save_complete;
342 callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
343
344 callbacks.save_yourself.client_data = xsmp;
345 callbacks.die.client_data = xsmp;
346 callbacks.save_complete.client_data = xsmp;
347 callbacks.shutdown_cancelled.client_data = xsmp;
348
349 client_id = NULL((void*)0);
350 error_string_ret[0] = '\0';
351 xsmp->connection =
352 SmcOpenConnection (NULL((void*)0), xsmp, SmProtoMajor1, SmProtoMinor0,
353 SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) |
354 SmcSaveCompleteProcMask(1L << 2) |
355 SmcShutdownCancelledProcMask(1L << 3),
356 &callbacks,
357 xsmp->client_id, &ret_client_id,
358 sizeof (error_string_ret), error_string_ret);
359
360 if (!xsmp->connection)
361 {
362 g_warning ("Failed to connect to the session manager: %s\n",
363 error_string_ret[0] ?
364 error_string_ret : "no error message given");
365 xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
366 return;
367 }
368
369 /* We expect a pointless initial SaveYourself if either (a) we
370 * didn't have an initial client ID, or (b) we DID have an initial
371 * client ID, but the server rejected it and gave us a new one.
372 */
373 if (!xsmp->client_id ||
374 (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0))
375 xsmp->expecting_initial_save_yourself = TRUE(!(0));
376
377 if (ret_client_id)
378 {
379 g_free (xsmp->client_id);
380 xsmp->client_id = g_strdup (ret_client_id)g_strdup_inline (ret_client_id);
381 free (ret_client_id);
382
383#if defined(GDK_WINDOWING_X11) || defined(HAVE_X11)
384 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(gdk_display_get_default ())); GType __t = ((gdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
385 gdk_x11_set_sm_client_id (xsmp->client_id);
386#endif
387
388 g_debug ("Got client ID \"%s\"", xsmp->client_id);
389 }
390
391 xsmp->state = XSMP_STATE_IDLE;
392
393 /* Do not set the initial properties until we reach the main loop,
394 * so that the application has a chance to call
395 * egg_set_desktop_file(). (This may also help the session manager
396 * have a better idea of when the application is fully up and
397 * running.)
398 */
399 xsmp->waiting_to_set_initial_properties = TRUE(!(0));
400 xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client);
401}
402
403static void
404sm_client_xsmp_set_restart_command (EggSMClient *client,
405 int argc,
406 const char **argv)
407{
408 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
409 int i;
410
411 g_strfreev (xsmp->restart_command);
412
413 xsmp->restart_command = g_new (char *, argc + 1)((char * *) g_malloc_n ((argc + 1), sizeof (char *)));
414 for (i = 0; i < argc; i++)
415 xsmp->restart_command[i] = g_strdup (argv[i])g_strdup_inline (argv[i]);
416 xsmp->restart_command[i] = NULL((void*)0);
417
418 xsmp->set_restart_command = TRUE(!(0));
419}
420
421static void
422sm_client_xsmp_set_discard_command (EggSMClient *client,
423 int argc,
424 const char **argv)
425{
426 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
427 int i;
428
429 g_strfreev (xsmp->discard_command);
430
431 xsmp->discard_command = g_new (char *, argc + 1)((char * *) g_malloc_n ((argc + 1), sizeof (char *)));
432 for (i = 0; i < argc; i++)
433 xsmp->discard_command[i] = g_strdup (argv[i])g_strdup_inline (argv[i]);
434 xsmp->discard_command[i] = NULL((void*)0);
435
436 xsmp->set_discard_command = TRUE(!(0));
437}
438
439static void
440sm_client_xsmp_will_quit (EggSMClient *client,
441 gboolean will_quit)
442{
443 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
444
445 if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED)
446 {
447 /* The session manager has already exited! Schedule a quit
448 * signal.
449 */
450 xsmp->waiting_to_emit_quit = TRUE(!(0));
451 update_pending_events (xsmp);
452 return;
453 }
454 else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
455 {
456 /* We received a ShutdownCancelled message while the application
457 * was interacting; Schedule a quit_cancelled signal.
458 */
459 xsmp->waiting_to_emit_quit_cancelled = TRUE(!(0));
460 update_pending_events (xsmp);
461 return;
462 }
463
464 g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT)do { if ((xsmp->state == XSMP_STATE_INTERACT)) { } else { g_return_if_fail_warning
("EggSMClient", ((const char*) (__func__)), "xsmp->state == XSMP_STATE_INTERACT"
); return; } } while (0)
;
465
466 g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True");
467 SmcInteractDone (xsmp->connection, !will_quit);
468
469 if (will_quit && xsmp->need_save_state)
470 save_state (xsmp);
471
472 g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False");
473 SmcSaveYourselfDone (xsmp->connection, will_quit);
474 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
475}
476
477static gboolean
478sm_client_xsmp_end_session (EggSMClient *client,
479 EggSMClientEndStyle style,
480 gboolean request_confirmation)
481{
482 EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
483 int save_type;
484
485 /* To end the session via XSMP, we have to send a
486 * SaveYourselfRequest. We aren't allowed to do that if anything
487 * else is going on, but we don't want to expose this fact to the
488 * application. So we do our best to patch things up here...
489 *
490 * In the worst case, this method might block for some length of
491 * time in process_ice_messages, but the only time that code path is
492 * honestly likely to get hit is if the application tries to end the
493 * session as the very first thing it does, in which case it
494 * probably won't actually block anyway. It's not worth gunking up
495 * the API to try to deal nicely with the other 0.01% of cases where
496 * this happens.
497 */
498
499 while (xsmp->state != XSMP_STATE_IDLE ||
500 xsmp->expecting_initial_save_yourself)
501 {
502 /* If we're already shutting down, we don't need to do anything. */
503 if (xsmp->shutting_down)
504 return TRUE(!(0));
505
506 switch (xsmp->state)
507 {
508 case XSMP_STATE_CONNECTION_CLOSED:
509 return FALSE(0);
510
511 case XSMP_STATE_SAVE_YOURSELF:
512 /* Trying to log out from the save_state callback? Whatever.
513 * Abort the save_state.
514 */
515 SmcSaveYourselfDone (xsmp->connection, FALSE(0));
516 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
517 break;
518
519 case XSMP_STATE_INTERACT_REQUEST:
520 case XSMP_STATE_INTERACT:
521 case XSMP_STATE_SHUTDOWN_CANCELLED:
522 /* Already in a shutdown-related state, just ignore
523 * the new shutdown request...
524 */
525 return TRUE(!(0));
526
527 case XSMP_STATE_IDLE:
528 if (xsmp->waiting_to_set_initial_properties)
529 sm_client_xsmp_set_initial_properties (xsmp);
530
531 if (!xsmp->expecting_initial_save_yourself)
532 break;
533 /* else fall through */
534
535 case XSMP_STATE_SAVE_YOURSELF_DONE:
536 /* We need to wait for some response from the server.*/
537 process_ice_messages (SmcGetIceConnection (xsmp->connection));
538 break;
539
540 default:
541 /* Hm... shouldn't happen */
542 return FALSE(0);
543 }
544 }
545
546 /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and
547 * the user chooses to save the session. But mate-session will do
548 * the wrong thing if we pass SmSaveBoth and the user chooses NOT to
549 * save the session... Sigh.
550 */
551 if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session"))
552 save_type = SmSaveBoth2;
553 else
554 save_type = SmSaveGlobal0;
555
556 g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : "");
557 SmcRequestSaveYourself (xsmp->connection,
558 save_type,
559 True1, /* shutdown */
560 SmInteractStyleAny2,
561 !request_confirmation, /* fast */
562 True1 /* global */);
563 return TRUE(!(0));
564}
565
566static gboolean
567idle_do_pending_events (gpointer data)
568{
569 EggSMClientXSMP *xsmp = data;
570 EggSMClient *client = data;
571
572 xsmp->idle = 0;
573
574 if (xsmp->waiting_to_emit_quit)
575 {
576 xsmp->waiting_to_emit_quit = FALSE(0);
577 egg_sm_client_quit (client);
578 goto out;
579 }
580
581 if (xsmp->waiting_to_emit_quit_cancelled)
582 {
583 xsmp->waiting_to_emit_quit_cancelled = FALSE(0);
584 egg_sm_client_quit_cancelled (client);
585 xsmp->state = XSMP_STATE_IDLE;
586 }
587
588 if (xsmp->waiting_to_save_myself)
589 {
590 xsmp->waiting_to_save_myself = FALSE(0);
591 do_save_yourself (xsmp);
592 }
593
594out:
595 return FALSE(0);
596}
597
598static void
599update_pending_events (EggSMClientXSMP *xsmp)
600{
601 gboolean want_idle =
602 xsmp->waiting_to_emit_quit ||
603 xsmp->waiting_to_emit_quit_cancelled ||
604 xsmp->waiting_to_save_myself;
605
606 if (want_idle)
607 {
608 if (xsmp->idle == 0)
609 xsmp->idle = g_idle_add (idle_do_pending_events, xsmp);
610 }
611 else
612 {
613 if (xsmp->idle != 0)
614 g_source_remove (xsmp->idle);
615 xsmp->idle = 0;
616 }
617}
618
619static void
620fix_broken_state (EggSMClientXSMP *xsmp, const char *message,
621 gboolean send_interact_done,
622 gboolean send_save_yourself_done)
623{
624 g_warning ("Received XSMP %s message in state %s: client or server error",
625 message, EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
626
627 /* Forget any pending SaveYourself plans we had */
628 xsmp->waiting_to_save_myself = FALSE(0);
629 update_pending_events (xsmp);
630
631 if (send_interact_done)
632 SmcInteractDone (xsmp->connection, False0);
633 if (send_save_yourself_done)
634 SmcSaveYourselfDone (xsmp->connection, True1);
635
636 xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE;
637}
638
639/* SM callbacks */
640
641static void
642xsmp_save_yourself (SmcConn smc_conn,
643 SmPointer client_data,
644 int save_type,
645 Boolint shutdown,
646 int interact_style,
647 Boolint fast)
648{
649 EggSMClientXSMP *xsmp = client_data;
650 gboolean wants_quit_requested;
651
652 g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s",
653 save_type == SmSaveLocal1 ? "SmSaveLocal" :
654 save_type == SmSaveGlobal0 ? "SmSaveGlobal" : "SmSaveBoth",
655 shutdown ? "Shutdown" : "!Shutdown",
656 interact_style == SmInteractStyleAny2 ? "SmInteractStyleAny" :
657 interact_style == SmInteractStyleErrors1 ? "SmInteractStyleErrors" :
658 "SmInteractStyleNone", fast ? "Fast" : "!Fast",
659 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
660
661 if (xsmp->state != XSMP_STATE_IDLE &&
662 xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED)
663 {
664 fix_broken_state (xsmp, "SaveYourself", FALSE(0), TRUE(!(0)));
665 return;
666 }
667
668 if (xsmp->waiting_to_set_initial_properties)
669 sm_client_xsmp_set_initial_properties (xsmp);
670
671 /* If this is the initial SaveYourself, ignore it; we've already set
672 * properties and there's no reason to actually save state too.
673 */
674 if (xsmp->expecting_initial_save_yourself)
675 {
676 xsmp->expecting_initial_save_yourself = FALSE(0);
677
678 if (save_type == SmSaveLocal1 &&
679 interact_style == SmInteractStyleNone0 &&
680 !shutdown && !fast)
681 {
682 g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself");
683 SmcSaveYourselfDone (xsmp->connection, True1);
684 /* As explained in the comment at the end of
685 * do_save_yourself(), SAVE_YOURSELF_DONE is the correct
686 * state here, not IDLE.
687 */
688 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
689 return;
690 }
691 else
692 g_warning ("First SaveYourself was not the expected one!");
693 }
694
695 /* Even ignoring the "fast" flag completely, there are still 18
696 * different combinations of save_type, shutdown and interact_style.
697 * We interpret them as follows:
698 *
699 * Type Shutdown Interact Interpretation
700 * G F A/E/N do nothing (1)
701 * G T N do nothing (1)*
702 * G T A/E quit_requested (2)
703 * L/B F A/E/N save_state (3)
704 * L/B T N save_state (3)*
705 * L/B T A/E quit_requested, then save_state (4)
706 *
707 * 1. Do nothing, because the SM asked us to do something
708 * uninteresting (save open files, but then don't quit
709 * afterward) or rude (save open files without asking the user
710 * for confirmation).
711 *
712 * 2. Request interaction and then emit ::quit_requested. This
713 * perhaps isn't quite correct for the SmInteractStyleErrors
714 * case, but we don't care.
715 *
716 * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these
717 * rows essentially get demoted to SmSaveLocal, because their
718 * Global halves correspond to "do nothing".
719 *
720 * 4. Request interaction, emit ::quit_requested, and then emit
721 * ::save_state after interacting. This is the SmSaveBoth
722 * equivalent of #2, but we also promote SmSaveLocal shutdown
723 * SaveYourselfs to SmSaveBoth here, because we want to give
724 * the user a chance to save open files before quitting.
725 *
726 * (* It would be nice if we could do something useful when the
727 * session manager sends a SaveYourself with shutdown True and
728 * SmInteractStyleNone. But we can't, so we just pretend it didn't
729 * even tell us it was shutting down. The docs for ::quit mention
730 * that it might not always be preceded by ::quit_requested.)
731 */
732
733 /* As an optimization, we don't actually request interaction and
734 * emit ::quit_requested if the application isn't listening to the
735 * signal.
736 */
737 wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT(egg_sm_client_get_type ())), 0, FALSE(0));
738
739 xsmp->need_save_state = (save_type != SmSaveGlobal0);
740 xsmp->need_quit_requested = (shutdown && wants_quit_requested &&
741 interact_style != SmInteractStyleNone0);
742 xsmp->interact_errors = (interact_style == SmInteractStyleErrors1);
743
744 xsmp->shutting_down = shutdown;
745
746 do_save_yourself (xsmp);
747}
748
749static void
750do_save_yourself (EggSMClientXSMP *xsmp)
751{
752 if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
753 {
754 /* The SM cancelled a previous SaveYourself, but we haven't yet
755 * had a chance to tell the application, so we can't start
756 * processing this SaveYourself yet.
757 */
758 xsmp->waiting_to_save_myself = TRUE(!(0));
759 update_pending_events (xsmp);
760 return;
761 }
762
763 if (xsmp->need_quit_requested)
764 {
765 xsmp->state = XSMP_STATE_INTERACT_REQUEST;
766
767 g_debug ("Sending InteractRequest(%s)",
768 xsmp->interact_errors ? "Error" : "Normal");
769 SmcInteractRequest (xsmp->connection,
770 xsmp->interact_errors ? SmDialogError0 : SmDialogNormal1,
771 xsmp_interact,
772 xsmp);
773 return;
774 }
775
776 if (xsmp->need_save_state)
777 {
778 save_state (xsmp);
779
780 /* Though unlikely, the client could have been disconnected
781 * while the application was saving its state.
782 */
783 if (!xsmp->connection)
784 return;
785 }
786
787 g_debug ("Sending SaveYourselfDone(True)");
788 SmcSaveYourselfDone (xsmp->connection, True1);
789
790 /* The client state diagram in the XSMP spec says that after a
791 * non-shutdown SaveYourself, we go directly back to "idle". But
792 * everything else in both the XSMP spec and the libSM docs
793 * disagrees.
794 */
795 xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
796}
797
798static void
799save_state (EggSMClientXSMP *xsmp)
800{
801 GKeyFile *state_file;
802 char *state_file_path, *data;
803 EggDesktopFile *desktop_file;
804 GPtrArray *restart, *discard;
805 int offset, fd;
806
807 /* We set xsmp->state before emitting save_state, but our caller is
808 * responsible for setting it back afterward.
809 */
810 xsmp->state = XSMP_STATE_SAVE_YOURSELF;
811
812 state_file = egg_sm_client_save_state ((EggSMClient *)xsmp);
813 if (!state_file)
814 {
815 restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL((void*)0));
816 set_properties (xsmp,
817 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
818 NULL((void*)0));
819 g_ptr_array_free (restart, TRUE(!(0)));
820
821 if (xsmp->set_discard_command)
822 {
823 discard = generate_command (xsmp->discard_command, NULL((void*)0), NULL((void*)0));
824 set_properties (xsmp,
825 ptrarray_prop (SmDiscardCommand"DiscardCommand", discard),
826 NULL((void*)0));
827 g_ptr_array_free (discard, TRUE(!(0)));
828 }
829 else
830 delete_properties (xsmp, SmDiscardCommand"DiscardCommand", NULL((void*)0));
831
832 return;
833 }
834
835 desktop_file = egg_get_desktop_file ();
836 if (desktop_file)
837 {
838 GKeyFile *merged_file;
839 char *desktop_file_path;
840
841 merged_file = g_key_file_new ();
842 desktop_file_path =
843 g_filename_from_uri (egg_desktop_file_get_source (desktop_file),
844 NULL((void*)0), NULL((void*)0));
845 if (desktop_file_path &&
846 g_key_file_load_from_file (merged_file, desktop_file_path,
847 G_KEY_FILE_KEEP_COMMENTS |
848 G_KEY_FILE_KEEP_TRANSLATIONS, NULL((void*)0)))
849 {
850 guint g, k, i;
851 char **groups, **keys, *value, *exec;
852
853 groups = g_key_file_get_groups (state_file, NULL((void*)0));
854 for (g = 0; groups[g]; g++)
855 {
856 keys = g_key_file_get_keys (state_file, groups[g], NULL((void*)0), NULL((void*)0));
857 for (k = 0; keys[k]; k++)
858 {
859 value = g_key_file_get_value (state_file, groups[g],
860 keys[k], NULL((void*)0));
861 if (value)
862 {
863 g_key_file_set_value (merged_file, groups[g],
864 keys[k], value);
865 g_free (value);
866 }
867 }
868 g_strfreev (keys);
869 }
870 g_strfreev (groups);
871
872 g_key_file_free (state_file);
873 state_file = merged_file;
874
875 /* Update Exec key using "--sm-client-state-file %k" */
876 restart = generate_command (xsmp->restart_command,
877 NULL((void*)0), "%k");
878 for (i = 0; i < restart->len; i++)
879 restart->pdata[i] = g_shell_quote (restart->pdata[i]);
880 g_ptr_array_add (restart, NULL((void*)0));
881 exec = g_strjoinv (" ", (char **)restart->pdata);
882 g_strfreev ((char **)restart->pdata);
883 g_ptr_array_free (restart, FALSE(0));
884
885 g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP"Desktop Entry",
886 EGG_DESKTOP_FILE_KEY_EXEC"Exec",
887 exec);
888 g_free (exec);
889 }
890 else
891 desktop_file = NULL((void*)0);
892
893 g_free (desktop_file_path);
894 }
895
896 /* Now write state_file to disk. (We can't use mktemp(), because
897 * that requires the filename to end with "XXXXXX", and we want
898 * it to end with ".desktop".)
899 */
900
901 data = g_key_file_to_data (state_file, NULL((void*)0), NULL((void*)0));
902 g_key_file_free (state_file);
903
904 offset = 0;
905 while (1)
906 {
907 state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s",
908 g_get_user_config_dir (),
909 G_DIR_SEPARATOR'/', G_DIR_SEPARATOR'/',
910 g_get_prgname (),
911 (long)time (NULL((void*)0)) + offset,
912 desktop_file ? "desktop" : "state");
913
914 fd = open (state_file_path, O_WRONLY01 | O_CREAT0100 | O_EXCL0200, 0644);
915 if (fd == -1)
916 {
917 if (errno(*__errno_location ()) == EEXIST17)
918 {
919 offset++;
920 g_free (state_file_path);
921 continue;
922 }
923 else if (errno(*__errno_location ()) == ENOTDIR20 || errno(*__errno_location ()) == ENOENT2)
924 {
925 char *sep = strrchr (state_file_path, G_DIR_SEPARATOR'/');
926
927 *sep = '\0';
928 if (g_mkdir_with_parents (state_file_path, 0755) != 0)
929 {
930 g_warning ("Could not create directory '%s'",
931 state_file_path);
932 g_free (state_file_path);
933 state_file_path = NULL((void*)0);
934 break;
935 }
936
937 continue;
938 }
939
940 g_warning ("Could not create file '%s': %s",
941 state_file_path, g_strerror (errno(*__errno_location ())));
942 g_free (state_file_path);
943 state_file_path = NULL((void*)0);
944 break;
945 }
946
947 close (fd);
948 g_file_set_contents (state_file_path, data, -1, NULL((void*)0));
949 break;
950 }
951 g_free (data);
952
953 restart = generate_command (xsmp->restart_command, xsmp->client_id,
954 state_file_path);
955 set_properties (xsmp,
956 ptrarray_prop (SmRestartCommand"RestartCommand", restart),
957 NULL((void*)0));
958 g_ptr_array_free (restart, TRUE(!(0)));
959
960 if (state_file_path)
961 {
962 set_properties (xsmp,
963 array_prop (SmDiscardCommand"DiscardCommand",
964 "/bin/rm", "-rf", state_file_path,
965 NULL((void*)0)),
966 NULL((void*)0));
967 g_free (state_file_path);
968 }
969}
970
971static void
972xsmp_interact (SmcConn smc_conn,
973 SmPointer client_data)
974{
975 EggSMClientXSMP *xsmp = client_data;
976 EggSMClient *client = client_data;
977
978 g_debug ("Received Interact message in state %s",
979 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
980
981 if (xsmp->state != XSMP_STATE_INTERACT_REQUEST)
982 {
983 fix_broken_state (xsmp, "Interact", TRUE(!(0)), TRUE(!(0)));
984 return;
985 }
986
987 xsmp->state = XSMP_STATE_INTERACT;
988 egg_sm_client_quit_requested (client);
989}
990
991static void
992xsmp_die (SmcConn smc_conn,
993 SmPointer client_data)
994{
995 EggSMClientXSMP *xsmp = client_data;
996 EggSMClient *client = client_data;
997
998 g_debug ("Received Die message in state %s",
999 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1000
1001 sm_client_xsmp_disconnect (xsmp);
1002 egg_sm_client_quit (client);
1003}
1004
1005static void
1006xsmp_save_complete (SmcConn smc_conn,
1007 SmPointer client_data)
1008{
1009 EggSMClientXSMP *xsmp = client_data;
1010
1011 g_debug ("Received SaveComplete message in state %s",
1012 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1013
1014 if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
1015 xsmp->state = XSMP_STATE_IDLE;
1016 else
1017 fix_broken_state (xsmp, "SaveComplete", FALSE(0), FALSE(0));
1018}
1019
1020static void
1021xsmp_shutdown_cancelled (SmcConn smc_conn,
1022 SmPointer client_data)
1023{
1024 EggSMClientXSMP *xsmp = client_data;
1025 EggSMClient *client = client_data;
1026
1027 g_debug ("Received ShutdownCancelled message in state %s",
1028 EGG_SM_CLIENT_XSMP_STATE (xsmp)(state_names[(xsmp)->state]));
1029
1030 xsmp->shutting_down = FALSE(0);
1031
1032 if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
1033 {
1034 /* We've finished interacting and now the SM has agreed to
1035 * cancel the shutdown.
1036 */
1037 xsmp->state = XSMP_STATE_IDLE;
1038 egg_sm_client_quit_cancelled (client);
1039 }
1040 else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
1041 {
1042 /* Hm... ok, so we got a shutdown SaveYourself, which got
1043 * cancelled, but the application was still interacting, so we
1044 * didn't tell it yet, and then *another* SaveYourself arrived,
1045 * which we must still be waiting to tell the app about, except
1046 * that now that SaveYourself has been cancelled too! Dizzy yet?
1047 */
1048 xsmp->waiting_to_save_myself = FALSE(0);
1049 update_pending_events (xsmp);
1050 }
1051 else
1052 {
1053 g_debug ("Sending SaveYourselfDone(False)");
1054 SmcSaveYourselfDone (xsmp->connection, False0);
1055
1056 if (xsmp->state == XSMP_STATE_INTERACT)
1057 {
1058 /* The application is currently interacting, so we can't
1059 * tell it about the cancellation yet; we will wait until
1060 * after it calls egg_sm_client_will_quit().
1061 */
1062 xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED;
1063 }
1064 else
1065 {
1066 /* The shutdown was cancelled before the application got a
1067 * chance to interact.
1068 */
1069 xsmp->state = XSMP_STATE_IDLE;
1070 }
1071 }
1072}
1073
1074/* Utilities */
1075
1076/* Create a restart/clone/Exec command based on @restart_command.
1077 * If @client_id is non-%NULL, add "--sm-client-id @client_id".
1078 * If @state_file is non-%NULL, add "--sm-client-state-file @state_file".
1079 *
1080 * None of the input strings are g_strdup()ed; the caller must keep
1081 * them around until it is done with the returned GPtrArray, and must
1082 * then free the array, but not its contents.
1083 */
1084static GPtrArray *
1085generate_command (char **restart_command, const char *client_id,
1086 const char *state_file)
1087{
1088 GPtrArray *cmd;
1089 int i;
1090
1091 cmd = g_ptr_array_new ();
1092 g_ptr_array_add (cmd, restart_command[0]);
1093
1094 if (client_id)
1095 {
1096 g_ptr_array_add (cmd, (char *)"--sm-client-id");
1097 g_ptr_array_add (cmd, (char *)client_id);
1098 }
1099
1100 if (state_file)
1101 {
1102 g_ptr_array_add (cmd, (char *)"--sm-client-state-file");
1103 g_ptr_array_add (cmd, (char *)state_file);
1104 }
1105
1106 for (i = 1; restart_command[i]; i++)
1107 g_ptr_array_add (cmd, restart_command[i]);
1108
1109 return cmd;
1110}
1111
1112/* Takes a NULL-terminated list of SmProp * values, created by
1113 * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and
1114 * frees them.
1115 */
1116static void
1117set_properties (EggSMClientXSMP *xsmp, ...)
1118{
1119 GPtrArray *props;
1120 SmProp *prop;
1121 va_list ap;
1122 guint i;
1123
1124 props = g_ptr_array_new ();
1125
1126 va_start (ap, xsmp)__builtin_va_start(ap, xsmp);
1127 while ((prop = va_arg (ap, SmProp *)__builtin_va_arg(ap, SmProp *)))
1128 g_ptr_array_add (props, prop);
1129 va_end (ap)__builtin_va_end(ap);
1130
1131 if (xsmp->connection)
1132 {
1133 SmcSetProperties (xsmp->connection, props->len,
1134 (SmProp **)props->pdata);
1135 }
1136
1137 for (i = 0; i < props->len; i++)
1138 {
1139 prop = props->pdata[i];
1140 g_free (prop->vals);
1141 g_free (prop);
1142 }
1143 g_ptr_array_free (props, TRUE(!(0)));
1144}
1145
1146/* Takes a NULL-terminated list of property names and deletes them. */
1147static void
1148delete_properties (EggSMClientXSMP *xsmp, ...)
1149{
1150 GPtrArray *props;
1151 char *prop;
1152 va_list ap;
1153
1154 if (!xsmp->connection)
1155 return;
1156
1157 props = g_ptr_array_new ();
1158
1159 va_start (ap, xsmp)__builtin_va_start(ap, xsmp);
1160 while ((prop = va_arg (ap, char *)__builtin_va_arg(ap, char *)))
1161 g_ptr_array_add (props, prop);
1162 va_end (ap)__builtin_va_end(ap);
1163
1164 SmcDeleteProperties (xsmp->connection, props->len,
1165 (char **)props->pdata);
1166
1167 g_ptr_array_free (props, TRUE(!(0)));
1168}
1169
1170/* Takes an array of strings and creates a LISTofARRAY8 property. The
1171 * strings are neither dupped nor freed; they need to remain valid
1172 * until you're done with the SmProp.
1173 */
1174static SmProp *
1175array_prop (const char *name, ...)
1176{
1177 SmProp *prop;
1178 SmPropValue pv;
1179 GArray *vals;
1180 char *value;
1181 va_list ap;
1182
1183 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1184 prop->name = (char *)name;
1185 prop->type = (char *)SmLISTofARRAY8"LISTofARRAY8";
1186
1187 vals = g_array_new (FALSE(0), FALSE(0), sizeof (SmPropValue));
1188
1189 va_start (ap, name)__builtin_va_start(ap, name);
1190 while ((value = va_arg (ap, char *)__builtin_va_arg(ap, char *)))
1191 {
1192 pv.length = strlen (value);
1193 pv.value = value;
1194 g_array_append_val (vals, pv)g_array_append_vals (vals, &(pv), 1);
1195 }
1196 va_end (ap)__builtin_va_end(ap);
1197
1198 prop->num_vals = vals->len;
1199 prop->vals = (SmPropValue *)vals->data;
1200
1201 g_array_free (vals, FALSE(0));
1202
1203 return prop;
1204}
1205
1206/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property.
1207 * The array contents are neither dupped nor freed; they need to
1208 * remain valid until you're done with the SmProp.
1209 */
1210static SmProp *
1211ptrarray_prop (const char *name, GPtrArray *values)
1212{
1213 SmProp *prop;
1214 SmPropValue pv;
1215 GArray *vals;
1216 guint i;
1217
1218 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1219 prop->name = (char *)name;
1220 prop->type = (char *)SmLISTofARRAY8"LISTofARRAY8";
1221
1222 vals = g_array_new (FALSE(0), FALSE(0), sizeof (SmPropValue));
1223
1224 for (i = 0; i < values->len; i++)
1225 {
1226 pv.length = strlen (values->pdata[i]);
1227 pv.value = values->pdata[i];
1228 g_array_append_val (vals, pv)g_array_append_vals (vals, &(pv), 1);
1229 }
1230
1231 prop->num_vals = vals->len;
1232 prop->vals = (SmPropValue *)vals->data;
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
1233
1234 g_array_free (vals, FALSE(0));
1235
1236 return prop;
1237}
1238
1239/* Takes a string and creates an ARRAY8 property. The string is
1240 * neither dupped nor freed; it needs to remain valid until you're
1241 * done with the SmProp.
1242 */
1243static SmProp *
1244string_prop (const char *name, const char *value)
1245{
1246 SmProp *prop;
1247
1248 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1249 prop->name = (char *)name;
1250 prop->type = (char *)SmARRAY8"ARRAY8";
1251
1252 prop->num_vals = 1;
1253 prop->vals = g_new (SmPropValue, 1)((SmPropValue *) g_malloc_n ((1), sizeof (SmPropValue)));
1254
1255 prop->vals[0].length = strlen (value);
1256 prop->vals[0].value = (char *)value;
1257
1258 return prop;
1259}
1260
1261/* Takes a char and creates a CARD8 property. */
1262static SmProp *
1263card8_prop (const char *name, unsigned char value)
1264{
1265 SmProp *prop;
1266 char *card8val;
1267
1268 /* To avoid having to allocate and free prop->vals[0], we cheat and
1269 * make vals a 2-element-long array and then use the second element
1270 * to store value.
1271 */
1272
1273 prop = g_new (SmProp, 1)((SmProp *) g_malloc_n ((1), sizeof (SmProp)));
1274 prop->name = (char *)name;
1275 prop->type = (char *)SmCARD8"CARD8";
1276
1277 prop->num_vals = 1;
1278 prop->vals = g_new (SmPropValue, 2)((SmPropValue *) g_malloc_n ((2), sizeof (SmPropValue)));
1279 card8val = (char *)(&prop->vals[1]);
1280 card8val[0] = value;
1281
1282 prop->vals[0].length = 1;
1283 prop->vals[0].value = card8val;
1284
1285 return prop;
1286}
1287
1288/* ICE code. This makes no effort to play nice with anyone else trying
1289 * to use libICE. Fortunately, no one uses libICE for anything other
1290 * than SM. (DCOP uses ICE, but it has its own private copy of
1291 * libICE.)
1292 *
1293 * When this moves to gtk, it will need to be cleverer, to avoid
1294 * tripping over old apps that use MateClient or that use libSM
1295 * directly.
1296 */
1297
1298#include <X11/ICE/ICElib.h>
1299#include <fcntl.h>
1300
1301static void ice_error_handler (IceConn ice_conn,
1302 Boolint swap,
1303 int offending_minor_opcode,
1304 unsigned long offending_sequence,
1305 int error_class,
1306 int severity,
1307 IcePointer values);
1308static void ice_io_error_handler (IceConn ice_conn);
1309static void ice_connection_watch (IceConn ice_conn,
1310 IcePointer client_data,
1311 Boolint opening,
1312 IcePointer *watch_data);
1313
1314static void
1315ice_init (void)
1316{
1317 IceSetIOErrorHandler (ice_io_error_handler);
1318 IceSetErrorHandler (ice_error_handler);
1319 IceAddConnectionWatch (ice_connection_watch, NULL((void*)0));
1320}
1321
1322static gboolean
1323process_ice_messages (IceConn ice_conn)
1324{
1325 IceProcessMessagesStatus status;
1326 status = IceProcessMessages (ice_conn, NULL((void*)0), NULL((void*)0));
1327
1328 switch (status)
1329 {
1330 case IceProcessMessagesSuccess:
1331 return TRUE(!(0));
1332
1333 case IceProcessMessagesIOError:
1334 sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn));
1335 return FALSE(0);
1336
1337 case IceProcessMessagesConnectionClosed:
1338 return FALSE(0);
1339
1340 default:
1341 g_assert_not_reached ()do { g_assertion_message_expr ("EggSMClient", "eggsmclient-xsmp.c"
, 1341, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1342 }
1343}
1344
1345static gboolean
1346ice_iochannel_watch (GIOChannel *channel,
1347 GIOCondition condition,
1348 gpointer client_data)
1349{
1350 return process_ice_messages (client_data);
1351}
1352
1353static void
1354ice_connection_watch (IceConn ice_conn,
1355 IcePointer client_data,
1356 Boolint opening,
1357 IcePointer *watch_data)
1358{
1359 guint watch_id;
1360
1361 if (opening)
1362 {
1363 GIOChannel *channel;
1364 int fd = IceConnectionNumber (ice_conn);
1365
1366 fcntl (fd, F_SETFD2, fcntl (fd, F_GETFD1, 0) | FD_CLOEXEC1);
1367 channel = g_io_channel_unix_new (fd);
1368 watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR,
1369 ice_iochannel_watch, ice_conn);
1370 g_io_channel_unref (channel);
1371
1372 *watch_data = GUINT_TO_POINTER (watch_id)((gpointer) (gulong) (watch_id));
1373 }
1374 else
1375 {
1376 watch_id = GPOINTER_TO_UINT (*watch_data)((guint) (gulong) (*watch_data));
1377 g_source_remove (watch_id);
1378 }
1379}
1380
1381static void
1382ice_error_handler (IceConn ice_conn,
1383 Boolint swap,
1384 int offending_minor_opcode,
1385 unsigned long offending_sequence,
1386 int error_class,
1387 int severity,
1388 IcePointer values)
1389{
1390 /* Do nothing */
1391}
1392
1393static void
1394ice_io_error_handler (IceConn ice_conn)
1395{
1396 /* Do nothing */
1397}
1398
1399static void
1400smc_error_handler (SmcConn smc_conn,
1401 Boolint swap,
1402 int offending_minor_opcode,
1403 unsigned long offending_sequence,
1404 int error_class,
1405 int severity,
1406 SmPointer values)
1407{
1408 /* Do nothing */
1409}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-d66062.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-d66062.html new file mode 100644 index 00000000..705a9153 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-d66062.html @@ -0,0 +1,2119 @@ + + + +mate-screenshot.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-screenshot/src/mate-screenshot.c
Warning:line 925, column 30
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-screenshot.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 static -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/mate-screenshot/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I . -I . -D MATELOCALEDIR="/usr/local/share/locale" -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -D _REENTRANT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-screenshot/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c mate-screenshot.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
2 * Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
3 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
4 * Copyright (C) 2012-2021 MATE Developers
5 *
6 * This file is part of MATE Utils.
7 *
8 * MATE Utils is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * MATE Utils is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#ifdef HAVE_CONFIG_H1
23#include <config.h>
24#endif
25
26#include <gdk/gdkx.h>
27#include <gdk/gdkkeysyms.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <errno(*__errno_location ()).h>
35#ifdef ENABLE_NLS1
36#include <locale.h>
37#endif /* ENABLE_NLS */
38#include <glib/gi18n.h>
39#include <gio/gio.h>
40#include <pwd.h>
41#include <X11/Xutil.h>
42#include <canberra-gtk.h>
43
44#include "screenshot-shadow.h"
45#include "screenshot-utils.h"
46#include "screenshot-save.h"
47#include "screenshot-dialog.h"
48#include "screenshot-xfer.h"
49
50#define SCREENSHOOTER_ICON"applets-screenshooter" "applets-screenshooter"
51
52#define MATE_SCREENSHOT_SCHEMA"org.mate.screenshot" "org.mate.screenshot"
53#define INCLUDE_BORDER_KEY"include-border" "include-border"
54#define INCLUDE_POINTER_KEY"include-pointer" "include-pointer"
55#define LAST_SAVE_DIRECTORY_KEY"last-save-directory" "last-save-directory"
56#define BORDER_EFFECT_KEY"border-effect" "border-effect"
57#define DELAY_KEY"delay" "delay"
58#define CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences" "org.mate.caja.preferences"
59
60enum
61{
62 COLUMN_NICK,
63 COLUMN_LABEL,
64 COLUMN_ID,
65
66 N_COLUMNS
67};
68
69typedef enum {
70 SCREENSHOT_EFFECT_NONE,
71 SCREENSHOT_EFFECT_SHADOW,
72 SCREENSHOT_EFFECT_BORDER
73} ScreenshotEffectType;
74
75typedef enum
76{
77 TEST_LAST_DIR = 0,
78 TEST_DESKTOP = 1,
79 TEST_TMP = 2,
80} TestType;
81
82typedef struct
83{
84 char *base_uris[3];
85 char *retval;
86 int iteration;
87 TestType type;
88 GdkWindow *window;
89 GdkRectangle *rectangle;
90} AsyncExistenceJob;
91
92static GdkPixbuf *screenshot = NULL((void*)0);
93
94/* Global variables*/
95static char *last_save_dir = NULL((void*)0);
96static char *temporary_file = NULL((void*)0);
97static gboolean save_immediately = FALSE(0);
98static GSettings *settings = NULL((void*)0);
99static gboolean interactive_arg = FALSE(0);
100static guint delay_arg = 0;
101
102/* Options */
103static gboolean noninteractive_clipboard_arg = FALSE(0);
104static gboolean take_window_shot = FALSE(0);
105static gboolean take_area_shot = FALSE(0);
106static gboolean include_border = FALSE(0);
107static gboolean include_pointer = TRUE(!(0));
108static char *border_effect = NULL((void*)0);
109static guint delay = 0;
110
111/* some local prototypes */
112static void display_help (GtkWindow *parent);
113static void save_done_notification (gpointer data);
114static char *get_desktop_dir (void);
115static void save_options (void);
116
117static GtkWidget *border_check = NULL((void*)0);
118static GtkWidget *effect_combo = NULL((void*)0);
119static GtkWidget *effect_label = NULL((void*)0);
120static GtkWidget *effects_vbox = NULL((void*)0);
121static GtkWidget *delay_hbox = NULL((void*)0);
122
123void loop_dialog_screenshot (void);
124
125static void
126display_help (GtkWindow *parent)
127{
128 GError *error = NULL((void*)0);
129
130 gtk_show_uri_on_window (parent,
131 "help:mate-user-guide/goseditmainmenu-53",
132 gtk_get_current_event_time (),
133 &error);
134
135 if (error)
136 {
137 screenshot_show_gerror_dialog (parent,
138 _("Error loading the help page")gettext ("Error loading the help page"),
139 error);
140 g_error_free (error);
141 }
142}
143
144static void
145interactive_dialog_response_cb (GtkDialog *dialog,
146 gint response,
147 gpointer user_data)
148{
149 switch (response)
150 {
151 case GTK_RESPONSE_HELP:
152 g_signal_stop_emission_by_name (dialog, "response");
153 display_help (GTK_WINDOW (dialog)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_window_get_type ()))))))
);
154 break;
155 default:
156 gtk_widget_hide (GTK_WIDGET (dialog)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_widget_get_type ()))))))
);
157 break;
158 }
159}
160
161#define TARGET_TOGGLE_DESKTOP0 0
162#define TARGET_TOGGLE_WINDOW1 1
163#define TARGET_TOGGLE_AREA2 2
164
165static void
166target_toggled_cb (GtkToggleButton *button,
167 gpointer data)
168{
169 int target_toggle = GPOINTER_TO_INT (data)((gint) (glong) (data));
170
171 if (gtk_toggle_button_get_active (button))
172 {
173 take_window_shot = (target_toggle == TARGET_TOGGLE_WINDOW1);
174 take_area_shot = (target_toggle == TARGET_TOGGLE_AREA2);
175
176 gtk_widget_set_sensitive (border_check, take_window_shot);
177 gtk_widget_set_sensitive (effect_combo, take_window_shot);
178 gtk_widget_set_sensitive (effect_label, take_window_shot);
179
180 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
181 gtk_widget_set_sensitive (effects_vbox, !take_area_shot);
182 }
183}
184
185static void
186delay_spin_value_changed_cb (GtkSpinButton *button)
187{
188 delay = gtk_spin_button_get_value_as_int (button);
189}
190
191static void
192include_border_toggled_cb (GtkToggleButton *button,
193 gpointer data)
194{
195 include_border = gtk_toggle_button_get_active (button);
196}
197
198static void
199include_pointer_toggled_cb (GtkToggleButton *button,
200 gpointer data)
201{
202 include_pointer = gtk_toggle_button_get_active (button);
203}
204
205static void
206effect_combo_changed_cb (GtkComboBox *combo,
207 gpointer user_data)
208{
209 GtkTreeIter iter;
210
211 if (gtk_combo_box_get_active_iter (combo, &iter))
212 {
213 GtkTreeModel *model;
214 gchar *effect;
215
216 model = gtk_combo_box_get_model (combo);
217 gtk_tree_model_get (model, &iter, COLUMN_NICK, &effect, -1);
218
219 g_assert (effect != NULL)do { if (effect != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "mate-screenshot.c", 219, ((const char*) (__func__
)), "effect != NULL"); } while (0)
;
220
221 g_free (border_effect);
222 border_effect = effect; /* gets free'd later */
223 }
224}
225
226static gint
227key_press_cb (GtkWidget* widget, GdkEventKey* event, gpointer data)
228{
229 if (event->keyval == GDK_KEY_F10xffbe)
230 {
231 display_help (GTK_WINDOW (widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((gtk_window_get_type ()))))))
);
232 return TRUE(!(0));
233 }
234
235 return FALSE(0);
236}
237
238typedef struct {
239 ScreenshotEffectType id;
240 const gchar *label;
241 const gchar *nick;
242} ScreenshotEffect;
243
244/* Translators:
245 * these are the names of the effects available which will be
246 * displayed inside a combo box in interactive mode for the user
247 * to chooser.
248 */
249static const ScreenshotEffect effects[] = {
250 { SCREENSHOT_EFFECT_NONE, N_("None")("None"), "none" },
251 { SCREENSHOT_EFFECT_SHADOW, N_("Drop shadow")("Drop shadow"), "shadow" },
252 { SCREENSHOT_EFFECT_BORDER, N_("Border")("Border"), "border" }
253};
254
255static guint n_effects = G_N_ELEMENTS (effects)(sizeof (effects) / sizeof ((effects)[0]));
256
257static GtkWidget *
258create_effects_combo (void)
259{
260 GtkWidget *retval;
261 GtkListStore *model;
262 GtkCellRenderer *renderer;
263 gint i;
264
265 model = gtk_list_store_new (N_COLUMNS,
266 G_TYPE_STRING((GType) ((16) << (2))),
267 G_TYPE_STRING((GType) ((16) << (2))),
268 G_TYPE_UINT((GType) ((7) << (2))));
269
270 for (i = 0; i < n_effects; i++)
271 {
272 GtkTreeIter iter;
273
274 gtk_list_store_insert (model, &iter, i);
275 gtk_list_store_set (model, &iter,
276 COLUMN_ID, effects[i].id,
277 COLUMN_LABEL, gettext (effects[i].label),
278 COLUMN_NICK, effects[i].nick,
279 -1);
280 }
281
282 retval = gtk_combo_box_new ();
283 gtk_combo_box_set_model (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
284 GTK_TREE_MODEL (model)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((gtk_tree_model_get_type ()))))))
);
285 g_object_unref (model);
286
287 switch (border_effect[0])
288 {
289 case 's': /* shadow */
290 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
291 SCREENSHOT_EFFECT_SHADOW);
292 break;
293 case 'b': /* border */
294 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
295 SCREENSHOT_EFFECT_BORDER);
296 break;
297 case 'n': /* none */
298 gtk_combo_box_set_active (GTK_COMBO_BOX (retval)((((GtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_combo_box_get_type ()))))))
,
299 SCREENSHOT_EFFECT_NONE);
300 break;
301 default:
302 break;
303 }
304
305 renderer = gtk_cell_renderer_text_new ();
306 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer, TRUE(!(0)));
307 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (retval)((((GtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_cell_layout_get_type ()))))))
, renderer,
308 "text", COLUMN_LABEL,
309 NULL((void*)0));
310
311 g_signal_connect (retval, "changed",g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
312 G_CALLBACK (effect_combo_changed_cb),g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
313 NULL)g_signal_connect_data ((retval), ("changed"), (((GCallback) (
effect_combo_changed_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
314
315 return retval;
316}
317
318static void
319create_effects_frame (GtkWidget *outer_vbox,
320 const gchar *frame_title)
321{
322 GtkWidget *main_vbox, *vbox, *hbox;
323 GtkWidget *label;
324 GtkWidget *check;
325 GtkWidget *combo;
326 gchar *title;
327
328 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
329 gtk_widget_set_sensitive (main_vbox, !take_area_shot);
330 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
331 gtk_widget_show (main_vbox);
332 effects_vbox = main_vbox;
333
334 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
335 label = gtk_label_new (title);
336 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
337 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
338 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
339 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
340 gtk_widget_show (label);
341 g_free (title);
342
343 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
344 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
345 gtk_widget_show (hbox);
346
347 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
348 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
349 gtk_widget_set_margin_start (vbox, 12);
350 gtk_widget_show (vbox);
351
352 /** Include pointer **/
353 check = gtk_check_button_new_with_mnemonic (_("Include _pointer")gettext ("Include _pointer"));
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_pointer);
355 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
356 G_CALLBACK (include_pointer_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
357 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_pointer_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
358 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
359 gtk_widget_show (check);
360
361 /** Include window border **/
362 check = gtk_check_button_new_with_mnemonic (_("Include the window _border")gettext ("Include the window _border"));
363 gtk_widget_set_sensitive (check, take_window_shot);
364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((check)), ((gtk_toggle_button_get_type ()))))))
, include_border);
365 g_signal_connect (check, "toggled",g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
366 G_CALLBACK (include_border_toggled_cb),g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
367 NULL)g_signal_connect_data ((check), ("toggled"), (((GCallback) (include_border_toggled_cb
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
368 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, check, FALSE(0), FALSE(0), 0);
369 gtk_widget_show (check);
370 border_check = check;
371
372 /** Effects **/
373 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
374 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
375 gtk_widget_show (hbox);
376
377 label = gtk_label_new_with_mnemonic (_("Apply _effect:")gettext ("Apply _effect:"));
378 gtk_widget_set_sensitive (label, take_window_shot);
379 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
380 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
381 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
382 gtk_widget_show (label);
383 effect_label = label;
384
385 combo = create_effects_combo ();
386 gtk_widget_set_sensitive (combo, take_window_shot);
387 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, combo, FALSE(0), FALSE(0), 0);
388 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, combo);
389 gtk_widget_show (combo);
390 effect_combo = combo;
391}
392
393static void
394create_screenshot_frame (GtkWidget *outer_vbox,
395 const gchar *frame_title)
396{
397 GtkWidget *main_vbox, *vbox, *hbox;
398 GtkWidget *radio;
399 GtkWidget *image;
400 GtkWidget *spin;
401 GtkWidget *label;
402 GtkAdjustment *adjust;
403 GSList *group;
404 gchar *title;
405
406 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
407 gtk_box_pack_start (GTK_BOX (outer_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((outer_vbox)), ((gtk_box_get_type ()))))))
, main_vbox, FALSE(0), FALSE(0), 0);
408 gtk_widget_show (main_vbox);
409
410 title = g_strconcat ("<b>", frame_title, "</b>", NULL((void*)0));
411 label = gtk_label_new (title);
412 gtk_label_set_use_markup (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
413 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
414 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
415 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
416 gtk_widget_show (label);
417 g_free (title);
418
419 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
420 gtk_box_pack_start (GTK_BOX (main_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
421 gtk_widget_show (hbox);
422
423 image = gtk_image_new_from_icon_name (SCREENSHOOTER_ICON"applets-screenshooter",
424 GTK_ICON_SIZE_DIALOG);
425
426 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image, FALSE(0), FALSE(0), 0);
427 gtk_widget_set_valign (image, GTK_ALIGN_START);
428 gtk_widget_show (image);
429
430 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
431 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
432 gtk_widget_show (vbox);
433
434 /** Grab whole desktop **/
435 group = NULL((void*)0);
436 radio = gtk_radio_button_new_with_mnemonic (group,
437 _("Grab the whole _desktop")gettext ("Grab the whole _desktop"));
438 if (take_window_shot || take_area_shot)
439 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, FALSE(0));
440 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
441 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
442 GINT_TO_POINTER (TARGET_TOGGLE_DESKTOP))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (0))), ((void*)0), (GConnectFlags) 0
)
;
443 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
444 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
445 gtk_widget_show (radio);
446
447 /** Grab current window **/
448 radio = gtk_radio_button_new_with_mnemonic (group,
449 _("Grab the current _window")gettext ("Grab the current _window"));
450 if (take_window_shot)
451 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
452 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
453 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
454 GINT_TO_POINTER (TARGET_TOGGLE_WINDOW))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (1))), ((void*)0), (GConnectFlags) 0
)
;
455 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
456 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)((((GtkRadioButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_radio_button_get_type ()))))))
);
457 gtk_widget_show (radio);
458
459 /** Grab area of the desktop **/
460 radio = gtk_radio_button_new_with_mnemonic (group,
461 _("Select _area to grab")gettext ("Select _area to grab"));
462 if (take_area_shot)
463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio)((((GtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((radio)), ((gtk_toggle_button_get_type ()))))))
, TRUE(!(0)));
464 g_signal_connect (radio, "toggled",g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
465 G_CALLBACK (target_toggled_cb),g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
466 GINT_TO_POINTER (TARGET_TOGGLE_AREA))g_signal_connect_data ((radio), ("toggled"), (((GCallback) (target_toggled_cb
))), (((gpointer) (glong) (2))), ((void*)0), (GConnectFlags) 0
)
;
467 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, radio, FALSE(0), FALSE(0), 0);
468 gtk_widget_show (radio);
469
470 /** Grab after delay **/
471 delay_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
472 gtk_widget_set_sensitive (delay_hbox, !take_area_shot);
473 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, delay_hbox, FALSE(0), FALSE(0), 0);
474 gtk_widget_show (delay_hbox);
475
476 /* translators: this is the first part of the "grab after a
477 * delay of <spin button> seconds".
478 */
479 label = gtk_label_new_with_mnemonic (_("Grab _after a delay of")gettext ("Grab _after a delay of"));
480 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
481 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
482 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
483 gtk_widget_show (label);
484
485 adjust = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) delay,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
486 0.0, 99.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
487 1.0, 1.0,((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
488 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new ((gdouble) delay, 0.0, 99.0, 1.0, 1.0
, 0.0))), ((gtk_adjustment_get_type ()))))))
;
489 spin = gtk_spin_button_new (adjust, 1.0, 0);
490 g_signal_connect (spin, "value-changed",g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
491 G_CALLBACK (delay_spin_value_changed_cb),g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
492 NULL)g_signal_connect_data ((spin), ("value-changed"), (((GCallback
) (delay_spin_value_changed_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
493 gtk_box_pack_start (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, spin, FALSE(0), FALSE(0), 0);
494 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, spin);
495 gtk_widget_show (spin);
496
497 /* translators: this is the last part of the "grab after a
498 * delay of <spin button> seconds".
499 */
500 label = gtk_label_new (_("seconds")gettext ("seconds"));
501 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
502 gtk_label_set_yalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.5);
503 gtk_box_pack_end (GTK_BOX (delay_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((delay_hbox)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
504 gtk_widget_show (label);
505}
506
507static GtkWidget *
508create_interactive_dialog (void)
509{
510 GtkWidget *retval;
511 GtkWidget *main_vbox;
512 GtkWidget *content_area;
513
514 retval = gtk_dialog_new ();
515 gtk_window_set_resizable (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, FALSE(0));
516 gtk_container_set_border_width (GTK_CONTAINER (retval)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_container_get_type ()))))))
, 5);
517 content_area = gtk_dialog_get_content_area (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
);
518 gtk_box_set_spacing (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, 2);
519 gtk_window_set_title (GTK_WINDOW (retval)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_window_get_type ()))))))
, _("Take Screenshot")gettext ("Take Screenshot"));
520
521 /* main container */
522 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
523 gtk_container_set_border_width (GTK_CONTAINER (main_vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((gtk_container_get_type ()))))))
, 5);
524 gtk_box_pack_start (GTK_BOX (content_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((content_area)), ((gtk_box_get_type ()))))))
, main_vbox, TRUE(!(0)), TRUE(!(0)), 0);
525 gtk_widget_show (main_vbox);
526
527 create_screenshot_frame (main_vbox, _("Take Screenshot")gettext ("Take Screenshot"));
528 create_effects_frame (main_vbox, _("Effects")gettext ("Effects"));
529 gtk_dialog_add_buttons (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
,
530 "gtk-help", GTK_RESPONSE_HELP,
531 "gtk-cancel", GTK_RESPONSE_CANCEL,
532 _("Take _Screenshot")gettext ("Take _Screenshot"), GTK_RESPONSE_OK,
533 NULL((void*)0));
534 gtk_dialog_set_default_response (GTK_DIALOG (retval)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
535
536 /* we need to block on "response" and keep showing the interactive
537 * dialog in case the user did choose "help"
538 */
539 g_signal_connect (retval, "response",g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
540 G_CALLBACK (interactive_dialog_response_cb),g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
541 NULL)g_signal_connect_data ((retval), ("response"), (((GCallback) (
interactive_dialog_response_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
542
543 g_signal_connect (retval, "key-press-event",g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
544 G_CALLBACK(key_press_cb),g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
545 NULL)g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (key_press_cb))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
546
547 return retval;
548}
549
550static void
551save_folder_to_settings (ScreenshotDialog *dialog)
552{
553 char *folder;
554
555 folder = screenshot_dialog_get_folder (dialog);
556 g_settings_set_string (settings,
557 LAST_SAVE_DIRECTORY_KEY"last-save-directory", folder);
558
559 g_free (folder);
560}
561
562static void
563set_recent_entry (ScreenshotDialog *dialog)
564{
565 char *uri, *app_exec = NULL((void*)0);
566 GtkRecentManager *recent;
567 GtkRecentData recent_data;
568 GAppInfo *app;
569 const char *exec_name = NULL((void*)0);
570 static char * groups[2] = { "Graphics", NULL((void*)0) };
571
572 app = g_app_info_get_default_for_type ("image/png", TRUE(!(0)));
573
574 if (!app) {
575 /* return early, as this would be an useless recent entry anyway. */
576 return;
577 }
578
579 uri = screenshot_dialog_get_uri (dialog);
580 recent = gtk_recent_manager_get_default ();
581
582 exec_name = g_app_info_get_executable (app);
583 app_exec = g_strjoin (" ", exec_name, "%u", NULL((void*)0));
584
585 recent_data.display_name = NULL((void*)0);
586 recent_data.description = NULL((void*)0);
587 recent_data.mime_type = "image/png";
588 recent_data.app_name = "MATE Screenshot";
589 recent_data.app_exec = app_exec;
590 recent_data.groups = groups;
591 recent_data.is_private = FALSE(0);
592
593 gtk_recent_manager_add_full (recent, uri, &recent_data);
594
595 g_object_unref (app);
596 g_free (app_exec);
597 g_free (uri);
598}
599
600static void
601error_dialog_response_cb (GtkDialog *d,
602 gint response,
603 ScreenshotDialog *dialog)
604{
605 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
606
607 screenshot_dialog_focus_entry (dialog);
608}
609
610static void
611save_callback (TransferResult result,
612 char *error_message,
613 gpointer data)
614{
615 ScreenshotDialog *dialog = data;
616 GtkWidget *toplevel;
617
618 toplevel = screenshot_dialog_get_toplevel (dialog);
619 screenshot_dialog_set_busy (dialog, FALSE(0));
620
621 if (result == TRANSFER_OK)
622 {
623 save_folder_to_settings (dialog);
624 set_recent_entry (dialog);
625 gtk_widget_destroy (toplevel);
626
627 /* we're done, stop the mainloop now */
628 gtk_main_quit ();
629 }
630 else if (result == TRANSFER_OVERWRITE ||
631 result == TRANSFER_CANCELLED)
632 {
633 /* user has canceled the overwrite dialog or the transfer itself, let him
634 * choose another name.
635 */
636 screenshot_dialog_focus_entry (dialog);
637 }
638 else /* result == TRANSFER_ERROR */
639 {
640 /* we had an error, display a dialog to the user and let him choose
641 * another name/location to save the screenshot.
642 */
643 GtkWidget *error_dialog;
644 char *uri;
645
646 uri = screenshot_dialog_get_uri (dialog);
647 error_dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_window_get_type ()))))))
,
648 GTK_DIALOG_DESTROY_WITH_PARENT,
649 GTK_MESSAGE_ERROR,
650 GTK_BUTTONS_OK,
651 _("Error while saving screenshot")gettext ("Error while saving screenshot"));
652 /* translators: first %s is the file path, second %s is the VFS error */
653 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog)((((GtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((error_dialog)), ((gtk_message_dialog_get_type
()))))))
,
654 _("Impossible to save the screenshot "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
655 "to %s.\n Error was %s.\n Please choose another "gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
656 "location and retry.")gettext ("Impossible to save the screenshot " "to %s.\n Error was %s.\n Please choose another "
"location and retry.")
, uri, error_message);
657 gtk_widget_show (error_dialog);
658 g_signal_connect (error_dialog,g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
659 "response",g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
660 G_CALLBACK (error_dialog_response_cb),g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
661 dialog)g_signal_connect_data ((error_dialog), ("response"), (((GCallback
) (error_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
662
663 g_free (uri);
664 }
665
666}
667
668static void
669try_to_save (ScreenshotDialog *dialog,
670 const char *target)
671{
672 GFile *source_file, *target_file;
673
674 g_assert (temporary_file)do { if (temporary_file) ; else g_assertion_message_expr (((gchar
*) 0), "mate-screenshot.c", 674, ((const char*) (__func__)), "temporary_file"
); } while (0)
;
675
676 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
677
678 source_file = g_file_new_for_path (temporary_file);
679 target_file = g_file_new_for_uri (target);
680
681 screenshot_xfer_uri (source_file,
682 target_file,
683 screenshot_dialog_get_toplevel (dialog),
684 save_callback, dialog);
685
686 /* screenshot_xfer_uri () holds a ref, so we can unref now */
687 g_object_unref (source_file);
688 g_object_unref (target_file);
689}
690
691static void
692save_done_notification (gpointer data)
693{
694 ScreenshotDialog *dialog = data;
695
696 temporary_file = g_strdup (screenshot_save_get_filename ())g_strdup_inline (screenshot_save_get_filename ());
697 screenshot_dialog_enable_dnd (dialog);
698
699 if (save_immediately)
700 {
701 GtkWidget *toplevel;
702
703 toplevel = screenshot_dialog_get_toplevel (dialog);
704 gtk_dialog_response (GTK_DIALOG (toplevel)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_dialog_get_type ()))))))
, GTK_RESPONSE_OK);
705 }
706}
707
708static void
709save_screenshot_in_clipboard (GdkDisplay *display, GdkPixbuf *screenshot)
710{
711 GtkClipboard *clipboard =
712 gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
713 gtk_clipboard_set_image (clipboard, screenshot);
714}
715
716static void
717screenshot_dialog_response_cb (GtkDialog *d,
718 gint response_id,
719 ScreenshotDialog *dialog)
720{
721 char *uri;
722
723 if (response_id == GTK_RESPONSE_HELP)
724 {
725 display_help (GTK_WINDOW (d)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_window_get_type ()))))))
);
726 }
727 else if (response_id == SCREENSHOT_RESPONSE_NEW22)
728 {
729 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
730 gtk_main_quit ();
731 interactive_arg = TRUE(!(0));
732 loop_dialog_screenshot();
733 }
734 else if (response_id == GTK_RESPONSE_OK)
735 {
736 uri = screenshot_dialog_get_uri (dialog);
737 if (temporary_file == NULL((void*)0))
738 {
739 save_immediately = TRUE(!(0));
740 screenshot_dialog_set_busy (dialog, TRUE(!(0)));
741 }
742 else
743 {
744 /* we've saved the temporary file, lets try to copy it to the
745 * correct location.
746 */
747 try_to_save (dialog, uri);
748 }
749 g_free (uri);
750 }
751 else if (response_id == SCREENSHOT_RESPONSE_COPY1)
752 {
753 save_screenshot_in_clipboard (gtk_widget_get_display (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
),
754 screenshot_dialog_get_screenshot (dialog));
755 }
756 else /* dialog was canceled */
757 {
758 gtk_widget_destroy (GTK_WIDGET (d)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((d)), ((gtk_widget_get_type ()))))))
);
759 gtk_main_quit ();
760 }
761}
762
763static void
764run_dialog (ScreenshotDialog *dialog)
765{
766 GtkWidget *toplevel;
767
768 toplevel = screenshot_dialog_get_toplevel (dialog);
769
770 gtk_widget_show (toplevel);
771
772 g_signal_connect (toplevel,g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
773 "response",g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
774 G_CALLBACK (screenshot_dialog_response_cb),g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
775 dialog)g_signal_connect_data ((toplevel), ("response"), (((GCallback
) (screenshot_dialog_response_cb))), (dialog), ((void*)0), (GConnectFlags
) 0)
;
776}
777
778static void
779play_sound_effect (GdkWindow *window)
780{
781 ca_context *c;
782 ca_proplist *p = NULL((void*)0);
783 int res;
784
785 c = ca_gtk_context_get ();
786
787 res = ca_proplist_create (&p);
788 if (res < 0)
789 goto done;
790
791 res = ca_proplist_sets (p, CA_PROP_EVENT_ID"event.id", "screen-capture");
792 if (res < 0)
793 goto done;
794
795 res = ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION"event.description", _("Screenshot taken")gettext ("Screenshot taken"));
796 if (res < 0)
797 goto done;
798
799 if (window != NULL((void*)0))
800 {
801 res = ca_proplist_setf (p,
802 CA_PROP_WINDOW_X11_XID"window.x11.xid",
803 "%lu",
804 (unsigned long) GDK_WINDOW_XID (window)(gdk_x11_window_get_xid (window)));
805 if (res < 0)
806 goto done;
807 }
808
809 ca_context_play_full (c, 0, p, NULL((void*)0), NULL((void*)0));
810
811 done:
812 if (p != NULL((void*)0))
813 ca_proplist_destroy (p);
814
815}
816
817static void
818finish_prepare_screenshot (char *initial_uri, GdkWindow *window, GdkRectangle *rectangle)
819{
820 ScreenshotDialog *dialog;
821 gboolean include_mask = (!take_window_shot && !take_area_shot);
822
823 /* always disable window border for full-desktop or selected-area screenshots */
824 if (!take_window_shot)
825 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, FALSE(0), include_mask);
826 else
827 {
828 screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, include_border, include_mask);
829
830 switch (border_effect[0])
831 {
832 case 's': /* shadow */
833 screenshot_add_shadow (&screenshot);
834 break;
835 case 'b': /* border */
836 screenshot_add_border (&screenshot);
837 break;
838 case 'n': /* none */
839 default:
840 break;
841 }
842 }
843
844 /* release now the lock, it was acquired when we were finding the window */
845 screenshot_release_lock ();
846
847 if (screenshot == NULL((void*)0))
848 {
849 screenshot_show_error_dialog (NULL((void*)0),
850 _("Unable to take a screenshot of the current window")gettext ("Unable to take a screenshot of the current window"),
851 NULL((void*)0));
852 exit (1);
853 }
854
855 play_sound_effect (window);
856
857 if (noninteractive_clipboard_arg) {
858 save_screenshot_in_clipboard (gdk_window_get_display (window), screenshot);
859 g_free (initial_uri);
860 /* Done here: */
861 gtk_main_quit ();
862 return;
863 }
864
865 dialog = screenshot_dialog_new (screenshot, initial_uri, take_window_shot);
866 g_free (initial_uri);
867
868 screenshot_save_start (screenshot, save_done_notification, dialog);
869
870 run_dialog (dialog);
871}
872
873static void
874async_existence_job_free (AsyncExistenceJob *job)
875{
876 if (!job)
877 return;
878
879 g_free (job->base_uris[1]);
880 g_free (job->base_uris[2]);
881
882 if (job->rectangle != NULL((void*)0))
883 g_slice_free (GdkRectangle, job->rectangle)do { if (1) g_slice_free1 (sizeof (GdkRectangle), (job->rectangle
)); else (void) ((GdkRectangle*) 0 == (job->rectangle)); }
while (0)
;
884
885 g_slice_free (AsyncExistenceJob, job)do { if (1) g_slice_free1 (sizeof (AsyncExistenceJob), (job))
; else (void) ((AsyncExistenceJob*) 0 == (job)); } while (0)
;
886}
887
888static gboolean
889check_file_done (gpointer user_data)
890{
891 AsyncExistenceJob *job = user_data;
892
893 finish_prepare_screenshot (job->retval, job->window, job->rectangle);
894
895 async_existence_job_free (job);
896
897 return FALSE(0);
898}
899
900static char *
901build_uri (AsyncExistenceJob *job)
902{
903 char *retval, *file_name;
904 char *timestamp;
905 GDateTime *d;
906
907 d = g_date_time_new_now_local ();
908 timestamp = g_date_time_format (d, "%Y-%m-%d %H-%M-%S");
909 g_date_time_unref (d);
910
911 if (job->iteration
22.1
Field 'iteration' is equal to 0
== 0)
23
Taking true branch
912 {
913 /* translators: this is the name of the file that gets made up
914 * with the screenshot if the entire screen is taken */
915 file_name = g_strdup_printf (_("Screenshot at %s.png")gettext ("Screenshot at %s.png"), timestamp);
916 }
917 else
918 {
919 /* translators: this is the name of the file that gets
920 * made up with the screenshot if the entire screen is
921 * taken */
922 file_name = g_strdup_printf (_("Screenshot at %s - %d.png")gettext ("Screenshot at %s - %d.png"), timestamp, job->iteration);
923 }
924
925 retval = g_build_filename (job->base_uris[job->type], file_name, NULL((void*)0));
24
Out of bound memory access (access exceeds upper limit of memory block)
926 g_free (file_name);
927 g_free (timestamp);
928
929 return retval;
930}
931
932static gboolean
933try_check_file (GIOSchedulerJob *io_job,
934 GCancellable *cancellable,
935 gpointer data)
936{
937 AsyncExistenceJob *job = data;
938 GFile *file;
939 GFileInfo *info;
940 GError *error;
941 char *uri;
942
943retry:
944 error = NULL((void*)0);
945 uri = build_uri (job);
22
Calling 'build_uri'
946 file = g_file_new_for_uri (uri);
947
948 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
949 G_FILE_QUERY_INFO_NONE, cancellable, &error);
950 if (info != NULL((void*)0))
1
Assuming 'info' is equal to NULL
2
Taking false branch
8
Assuming 'info' is equal to NULL
9
Taking false branch
15
Assuming 'info' is equal to NULL
16
Taking false branch
951 {
952 /* file already exists, iterate again */
953 g_object_unref (info);
954 g_object_unref (file);
955 g_free (uri);
956
957 (job->iteration)++;
958
959 goto retry;
960 }
961 else
962 {
963 /* see the error to check whether the location is not accessible
964 * or the file does not exist.
965 */
966 if (error->code == G_IO_ERROR_NOT_FOUND)
3
Assuming field 'code' is not equal to G_IO_ERROR_NOT_FOUND
4
Taking false branch
10
Assuming field 'code' is not equal to G_IO_ERROR_NOT_FOUND
11
Taking false branch
17
Assuming field 'code' is equal to G_IO_ERROR_NOT_FOUND
18
Taking true branch
967 {
968 GFile *parent;
969
970 /* if the parent directory doesn't exist as well, forget the saved
971 * directory and treat this as a generic error.
972 */
973
974 parent = g_file_get_parent (file);
975
976 if (!g_file_query_exists (parent, NULL((void*)0)))
19
Assuming the condition is true
20
Taking true branch
977 {
978 (job->type)++;
979 job->iteration = 0;
980
981 g_object_unref (file);
982 g_object_unref (parent);
983 goto retry;
21
Control jumps to line 944
984 }
985 else
986 {
987 job->retval = uri;
988
989 g_object_unref (parent);
990 goto out;
991 }
992 }
993 else
994 {
995 /* another kind of error, assume this location is not
996 * accessible.
997 */
998 g_free (uri);
999 if (job->type == TEST_TMP)
5
Assuming field 'type' is not equal to TEST_TMP
6
Taking false branch
12
Assuming field 'type' is not equal to TEST_TMP
13
Taking false branch
1000 {
1001 job->retval = NULL((void*)0);
1002 goto out;
1003 }
1004 else
1005 {
1006 (job->type)++;
1007 job->iteration = 0;
1008
1009 g_error_free (error);
1010 g_object_unref (file);
1011 goto retry;
7
Control jumps to line 944
14
Control jumps to line 944
1012 }
1013 }
1014 }
1015
1016out:
1017 g_error_free (error);
1018 g_object_unref (file);
1019
1020 g_io_scheduler_job_send_to_mainloop_async (io_job,
1021 check_file_done,
1022 job,
1023 NULL((void*)0));
1024 return FALSE(0);
1025}
1026
1027static GdkWindow *
1028find_current_window (void)
1029{
1030 GdkWindow *window;
1031
1032 if (!screenshot_grab_lock ())
1033 exit (0);
1034
1035 if (take_window_shot)
1036 {
1037 window = screenshot_find_current_window ();
1038 if (!window)
1039 {
1040 take_window_shot = FALSE(0);
1041 window = gdk_get_default_root_window ();
1042 }
1043 }
1044 else
1045 {
1046 window = gdk_get_default_root_window ();
1047 }
1048
1049 return window;
1050}
1051
1052static void
1053push_check_file_job (GdkRectangle *rectangle)
1054{
1055 AsyncExistenceJob *job;
1056
1057 job = g_slice_new0 (AsyncExistenceJob)((AsyncExistenceJob*) g_slice_alloc0 (sizeof (AsyncExistenceJob
)))
;
1058 job->base_uris[0] = last_save_dir;
1059 /* we'll have to free these two */
1060 job->base_uris[1] = get_desktop_dir ();
1061 job->base_uris[2] = g_strconcat ("file://", g_get_tmp_dir (), NULL((void*)0));
1062 job->iteration = 0;
1063 job->type = TEST_LAST_DIR;
1064 job->window = find_current_window ();
1065
1066 if (rectangle != NULL((void*)0))
1067 {
1068 job->rectangle = g_slice_new0 (GdkRectangle)((GdkRectangle*) g_slice_alloc0 (sizeof (GdkRectangle)));
1069 job->rectangle->x = rectangle->x;
1070 job->rectangle->y = rectangle->y;
1071 job->rectangle->width = rectangle->width;
1072 job->rectangle->height = rectangle->height;
1073 }
1074
1075 /* Check if the area selection was cancelled */
1076 if (job->rectangle &&
1077 (job->rectangle->width == 0 || job->rectangle->height == 0))
1078 {
1079 async_existence_job_free (job);
1080 gtk_main_quit ();
1081 return;
1082 }
1083
1084 g_io_scheduler_push_job (try_check_file,
1085 job,
1086 NULL((void*)0),
1087 0, NULL((void*)0));
1088
1089}
1090
1091static void
1092rectangle_found_cb (GdkRectangle *rectangle)
1093{
1094 push_check_file_job (rectangle);
1095}
1096
1097static void
1098prepare_screenshot (void)
1099{
1100 if (take_area_shot)
1101 screenshot_select_area_async (rectangle_found_cb);
1102 else
1103 push_check_file_job (NULL((void*)0));
1104}
1105
1106static gboolean
1107prepare_screenshot_timeout (gpointer data)
1108{
1109 prepare_screenshot ();
1110 save_options ();
1111
1112 return FALSE(0);
1113}
1114
1115static gchar *
1116get_desktop_dir (void)
1117{
1118 gboolean desktop_is_home_dir = FALSE(0);
1119 gchar *desktop_dir;
1120
1121 /* Check if caja schema is installed before trying to read settings */
1122 GSettingsSchema *schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1123 CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences",
1124 FALSE(0));
1125
1126 if (schema != NULL((void*)0)) {
1127 GSettings *caja_prefs;
1128
1129 caja_prefs = g_settings_new (CAJA_PREFERENCES_SCHEMA"org.mate.caja.preferences");
1130 desktop_is_home_dir = g_settings_get_boolean (caja_prefs, "desktop-is-home-dir");
1131
1132 g_object_unref (caja_prefs);
1133 g_settings_schema_unref (schema);
1134 }
1135
1136 if (desktop_is_home_dir)
1137 desktop_dir = g_strconcat ("file://", g_get_home_dir (), NULL((void*)0));
1138 else
1139 desktop_dir = g_strconcat ("file://", g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), NULL((void*)0));
1140
1141 return desktop_dir;
1142}
1143
1144/* Taken from mate-vfs-utils.c */
1145static char *
1146expand_initial_tilde (const char *path)
1147{
1148 char *slash_after_user_name, *user_name;
1149 struct passwd *passwd_file_entry;
1150
1151 if (path[1] == '/' || path[1] == '\0') {
1152 return g_strconcat (g_get_home_dir (), &path[1], NULL((void*)0));
1153 }
1154
1155 slash_after_user_name = strchr (&path[1], '/');
1156 if (slash_after_user_name == NULL((void*)0)) {
1157 user_name = g_strdup (&path[1])g_strdup_inline (&path[1]);
1158 } else {
1159 user_name = g_strndup (&path[1],
1160 slash_after_user_name - &path[1]);
1161 }
1162 passwd_file_entry = getpwnam (user_name);
1163 g_free (user_name);
1164
1165 if (passwd_file_entry == NULL((void*)0) || passwd_file_entry->pw_dir == NULL((void*)0)) {
1166 return g_strdup (path)g_strdup_inline (path);
1167 }
1168
1169 return g_strconcat (passwd_file_entry->pw_dir,
1170 slash_after_user_name,
1171 NULL((void*)0));
1172}
1173
1174/* Load options */
1175static void
1176load_options (void)
1177{
1178 /* Find various dirs */
1179 last_save_dir = g_settings_get_string (settings,
1180 LAST_SAVE_DIRECTORY_KEY"last-save-directory");
1181
1182 if (*last_save_dir == '\0')
1183 {
1184 g_free (last_save_dir);
1185 last_save_dir = get_desktop_dir ();
1186 }
1187 else if (last_save_dir[0] == '~')
1188 {
1189 char *tmp = expand_initial_tilde (last_save_dir);
1190 g_free (last_save_dir);
1191 last_save_dir = tmp;
1192 }
1193
1194 include_border = g_settings_get_boolean (settings,
1195 INCLUDE_BORDER_KEY"include-border");
1196
1197 include_pointer = g_settings_get_boolean (settings,
1198 INCLUDE_POINTER_KEY"include-pointer");
1199
1200 border_effect = g_settings_get_string (settings,
1201 BORDER_EFFECT_KEY"border-effect");
1202 if (!border_effect)
1203 border_effect = g_strdup ("none")g_strdup_inline ("none");
1204
1205 delay = g_settings_get_int (settings, DELAY_KEY"delay");
1206}
1207
1208static void
1209save_options (void)
1210{
1211 g_settings_set_boolean (settings,
1212 INCLUDE_BORDER_KEY"include-border", include_border);
1213 g_settings_set_boolean (settings,
1214 INCLUDE_POINTER_KEY"include-pointer", include_pointer);
1215 g_settings_set_int (settings, DELAY_KEY"delay", delay);
1216 g_settings_set_string (settings,
1217 BORDER_EFFECT_KEY"border-effect", border_effect);
1218}
1219
1220void
1221loop_dialog_screenshot (void)
1222{
1223 /* interactive mode overrides everything */
1224 if (interactive_arg)
1225 {
1226 GtkWidget *dialog;
1227 gint response;
1228
1229 dialog = create_interactive_dialog ();
1230 response = gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
1231 gtk_widget_destroy (dialog);
1232
1233 switch (response)
1234 {
1235 case GTK_RESPONSE_DELETE_EVENT:
1236 case GTK_RESPONSE_CANCEL:
1237 return;
1238 case GTK_RESPONSE_OK:
1239 break;
1240 default:
1241 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "mate-screenshot.c"
, 1241, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1242 break;
1243 }
1244 }
1245
1246 if (((delay > 0 && interactive_arg) || delay_arg > 0) &&
1247 !take_area_shot)
1248 {
1249 g_timeout_add (delay * 1000,
1250 prepare_screenshot_timeout,
1251 NULL((void*)0));
1252 }
1253 else
1254 {
1255 if (interactive_arg)
1256 {
1257 /* HACK: give time to the dialog to actually disappear.
1258 * We don't have any way to tell when the compositor has finished
1259 * re-drawing.
1260 */
1261 g_timeout_add (200,
1262 prepare_screenshot_timeout, NULL((void*)0));
1263 }
1264 else
1265 g_idle_add (prepare_screenshot_timeout, NULL((void*)0));
1266 }
1267
1268 gtk_main ();
1269}
1270
1271/* main */
1272int
1273main (int argc, char *argv[])
1274{
1275 GOptionContext *context;
1276 gboolean window_arg = FALSE(0);
1277 gboolean area_arg = FALSE(0);
1278 gboolean include_border_arg = FALSE(0);
1279 gboolean disable_border_arg = FALSE(0);
1280 gchar *border_effect_arg = NULL((void*)0);
1281 gboolean version_arg = FALSE(0);
1282 GError *error = NULL((void*)0);
1283
1284 const GOptionEntry entries[] = {
1285 { "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen")("Grab a window instead of the entire screen"), NULL((void*)0) },
1286 { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen")("Grab an area of the screen instead of the entire screen"), NULL((void*)0) },
1287 { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &noninteractive_clipboard_arg, N_("Send grabbed area directly to the clipboard")("Send grabbed area directly to the clipboard"), NULL((void*)0) },
1288 { "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot")("Include the window border with the screenshot"), NULL((void*)0) },
1289 { "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot")("Remove the window border from the screenshot"), NULL((void*)0) },
1290 { "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]")("Take screenshot after specified delay [in seconds]"), N_("seconds")("seconds") },
1291 { "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)")("Effect to add to the border (shadow, border or none)"), N_("effect")("effect") },
1292 { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options")("Interactively set options"), NULL((void*)0) },
1293 { "version", 0, 0, G_OPTION_ARG_NONE, &version_arg, N_("Print version information and exit")("Print version information and exit"), NULL((void*)0) },
1294 { NULL((void*)0), 0, 0, G_OPTION_ARG_NONE, NULL((void*)0), NULL((void*)0), NULL((void*)0) },
1295 };
1296
1297#ifdef ENABLE_NLS1
1298 setlocale (LC_ALL6, "");
1299 bindtextdomain (GETTEXT_PACKAGE"mate-utils", MATELOCALEDIR"/usr/local/share/locale");
1300 bind_textdomain_codeset (GETTEXT_PACKAGE"mate-utils", "UTF-8");
1301 textdomain (GETTEXT_PACKAGE"mate-utils");
1302#endif /* ENABLE_NLS */
1303
1304 context = g_option_context_new (_("Take a picture of the screen")gettext ("Take a picture of the screen"));
1305 g_option_context_set_ignore_unknown_options (context, FALSE(0));
1306 g_option_context_set_help_enabled (context, TRUE(!(0)));
1307 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE"mate-utils");
1308 g_option_context_add_group (context, gtk_get_option_group (TRUE(!(0))));
1309
1310 g_option_context_parse (context, &argc, &argv, &error);
1311
1312 if (error) {
1313 g_critical ("Unable to parse arguments: %s", error->message);
1314 g_error_free (error);
1315 g_option_context_free (context);
1316 exit (1);
1317 }
1318
1319 g_option_context_free (context);
1320
1321 if (version_arg) {
1322 g_print ("%s %s\n", g_get_application_name (), VERSION"1.27.0");
1323 exit (EXIT_SUCCESS0);
1324 }
1325
1326 if (interactive_arg && noninteractive_clipboard_arg) {
1327 g_printerr (_("Conflicting options: --clipboard and --interactive should not be "gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
1328 "used at the same time.\n")gettext ("Conflicting options: --clipboard and --interactive should not be "
"used at the same time.\n")
);
1329 exit (1);
1330 }
1331
1332 if (window_arg && area_arg) {
1333 g_printerr (_("Conflicting options: --window and --area should not be "gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
1334 "used at the same time.\n")gettext ("Conflicting options: --window and --area should not be "
"used at the same time.\n")
);
1335 exit (1);
1336 }
1337
1338 gtk_window_set_default_icon_name (SCREENSHOOTER_ICON"applets-screenshooter");
1339
1340 settings = g_settings_new (MATE_SCREENSHOT_SCHEMA"org.mate.screenshot");
1341 load_options ();
1342 /* allow the command line to override options */
1343 if (window_arg)
1344 take_window_shot = TRUE(!(0));
1345
1346 if (area_arg)
1347 take_area_shot = TRUE(!(0));
1348
1349 if (include_border_arg)
1350 include_border = TRUE(!(0));
1351
1352 if (disable_border_arg)
1353 include_border = FALSE(0);
1354
1355 if (border_effect_arg)
1356 {
1357 g_free (border_effect);
1358 border_effect = border_effect_arg;
1359 }
1360
1361 if (delay_arg > 0)
1362 delay = delay_arg;
1363
1364 loop_dialog_screenshot();
1365
1366 return EXIT_SUCCESS0;
1367}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-e4b97b.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-e4b97b.html new file mode 100644 index 00000000..40e0f5d0 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-e4b97b.html @@ -0,0 +1,3640 @@ + + + +gdict-defbox.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-dictionary/libgdict/gdict-defbox.c
Warning:line 865, column 18
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gdict-defbox.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/mate-dictionary/libgdict -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Gdict" -D DATADIR="/usr/local/share" -D LIBDIR="/usr/local/lib" -D SYSCONFDIR="/usr/local/etc" -D PREFIX="/usr/local" -D MATELOCALEDIR="/usr/local/share/locale" -D GDICTSOURCESDIR="/usr/local/share/mate-dict/sources" -D GDICT_ENABLE_INTERNALS -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D G_DISABLE_CAST_CHECKS -D PIC -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c gdict-defbox.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2005-2006 Emmanuele Bassi <ebassi@gmail.com>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20/**
21 * SECTION:gdict-defbox
22 * @short_description: Display the list of definitions for a word
23 *
24 * The #GdictDefbox widget is a composite widget showing the list of
25 * definitions for a word. It queries the passed #GdictContext and displays
26 * the list of #GdictDefinition<!-- -->s obtained.
27 *
28 * It provides syntax highlighting, clickable links and an embedded find
29 * bar.
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 <stdarg.h>
40
41#include <gtk/gtk.h>
42#include <gdk/gdkkeysyms.h>
43#include <glib/gi18n-lib.h>
44
45#include "gdict-defbox.h"
46#include "gdict-utils.h"
47#include "gdict-debug.h"
48#include "gdict-private.h"
49#include "gdict-enum-types.h"
50#include "gdict-marshal.h"
51
52#define QUERY_MARGIN48 48
53#define ERROR_MARGIN24 24
54
55typedef struct
56{
57 GdictDefinition *definition;
58
59 gint begin;
60} Definition;
61
62struct _GdictDefboxPrivate
63{
64 GtkWidget *text_view;
65
66 /* the "find" pane */
67 GtkWidget *find_pane;
68 GtkWidget *find_entry;
69 GtkWidget *find_next;
70 GtkWidget *find_prev;
71 GtkWidget *find_label;
72
73 GtkWidget *progress_dialog;
74
75 GtkTextBuffer *buffer;
76
77 GdictContext *context;
78 GSList *definitions;
79
80 gchar *word;
81 gchar *database;
82 gchar *font_name;
83
84 guint show_find : 1;
85 guint is_searching : 1;
86 guint is_hovering : 1;
87
88 GdkCursor *busy_cursor;
89 GdkCursor *hand_cursor;
90 GdkCursor *regular_cursor;
91
92 guint start_id;
93 guint end_id;
94 guint define_id;
95 guint error_id;
96 guint hide_timeout;
97
98 GtkTextTag *link_tag;
99 GtkTextTag *visited_link_tag;
100};
101
102enum
103{
104 PROP_0,
105
106 PROP_CONTEXT,
107 PROP_WORD,
108 PROP_DATABASE,
109 PROP_FONT_NAME,
110 PROP_COUNT
111};
112
113enum
114{
115 SHOW_FIND,
116 HIDE_FIND,
117 FIND_NEXT,
118 FIND_PREVIOUS,
119 LINK_CLICKED,
120
121 LAST_SIGNAL
122};
123
124static guint gdict_defbox_signals[LAST_SIGNAL] = { 0 };
125
126G_DEFINE_TYPE_WITH_PRIVATE (GdictDefbox, gdict_defbox, GTK_TYPE_BOX)static void gdict_defbox_init (GdictDefbox *self); static void
gdict_defbox_class_init (GdictDefboxClass *klass); static GType
gdict_defbox_get_type_once (void); static gpointer gdict_defbox_parent_class
= ((void*)0); static gint GdictDefbox_private_offset; static
void gdict_defbox_class_intern_init (gpointer klass) { gdict_defbox_parent_class
= g_type_class_peek_parent (klass); if (GdictDefbox_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &GdictDefbox_private_offset
); gdict_defbox_class_init ((GdictDefboxClass*) klass); } __attribute__
((__unused__)) static inline gpointer gdict_defbox_get_instance_private
(GdictDefbox *self) { return (((gpointer) ((guint8*) (self) +
(glong) (GdictDefbox_private_offset)))); } GType gdict_defbox_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_defbox_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_defbox_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_box_get_type ()), g_intern_static_string ("GdictDefbox"
), sizeof (GdictDefboxClass), (GClassInitFunc)(void (*)(void)
) gdict_defbox_class_intern_init, sizeof (GdictDefbox), (GInstanceInitFunc
)(void (*)(void)) gdict_defbox_init, (GTypeFlags) 0); { {{ GdictDefbox_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (GdictDefboxPrivate
)); };} } return g_define_type_id; }
127
128static Definition *
129definition_new (void)
130{
131 Definition *def;
132
133 def = g_slice_new (Definition)((Definition*) g_slice_alloc (sizeof (Definition)));
134 def->definition = NULL((void*)0);
135 def->begin = -1;
136
137 return def;
138}
139
140static void
141definition_free (Definition *def)
142{
143 if (!def)
144 return;
145
146 gdict_definition_unref (def->definition);
147 g_slice_free (Definition, def)do { if (1) g_slice_free1 (sizeof (Definition), (def)); else (
void) ((Definition*) 0 == (def)); } while (0)
;
148}
149
150static void
151gdict_defbox_dispose (GObject *gobject)
152{
153 GdictDefbox *defbox = GDICT_DEFBOX (gobject)((((GdictDefbox*) (void *) ((gobject)))));
154 GdictDefboxPrivate *priv = defbox->priv;
155
156 if (priv->start_id)
157 {
158 g_signal_handler_disconnect (priv->context, priv->start_id);
159 g_signal_handler_disconnect (priv->context, priv->end_id);
160 g_signal_handler_disconnect (priv->context, priv->define_id);
161
162 priv->start_id = 0;
163 priv->end_id = 0;
164 priv->define_id = 0;
165 }
166
167 if (priv->error_id)
168 {
169 g_signal_handler_disconnect (priv->context, priv->error_id);
170 priv->error_id = 0;
171 }
172
173 if (priv->context)
174 {
175 g_object_unref (priv->context);
176 priv->context = NULL((void*)0);
177 }
178
179 if (priv->buffer)
180 {
181 g_object_unref (priv->buffer);
182 priv->buffer = NULL((void*)0);
183 }
184
185 if (priv->busy_cursor)
186 {
187 g_object_unref (priv->busy_cursor);
188 priv->busy_cursor = NULL((void*)0);
189 }
190
191 if (priv->hand_cursor)
192 {
193 g_object_unref (priv->hand_cursor);
194 priv->hand_cursor = NULL((void*)0);
195 }
196
197 if (priv->regular_cursor)
198 {
199 g_object_unref (priv->regular_cursor);
200 priv->regular_cursor = NULL((void*)0);
201 }
202
203 g_clear_pointer (&priv->word, g_free)do { _Static_assert (sizeof *(&priv->word) == sizeof (
gpointer), "Expression evaluates to false"); __typeof__ ((&
priv->word)) _pp = (&priv->word); __typeof__ (*(&
priv->word)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free
) (_ptr); } while (0)
;
204
205 G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->dispose (gobject);
206}
207
208static void
209gdict_defbox_finalize (GObject *object)
210{
211 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
212 GdictDefboxPrivate *priv = defbox->priv;
213
214 g_free (priv->database);
215 g_free (priv->word);
216 g_free (priv->font_name);
217
218 if (priv->definitions)
219 {
220 g_slist_free_full (priv->definitions, (GDestroyNotify) definition_free);
221 priv->definitions = NULL((void*)0);
222 }
223
224 G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->finalize (object);
225}
226
227static void
228set_gdict_context (GdictDefbox *defbox,
229 GdictContext *context)
230{
231 GdictDefboxPrivate *priv;
232
233 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
234
235 priv = defbox->priv;
236 if (priv->context)
237 {
238 if (priv->start_id)
239 {
240 GDICT_NOTE (DEFBOX, "Removing old context handlers");
241
242 g_signal_handler_disconnect (priv->context, priv->start_id);
243 g_signal_handler_disconnect (priv->context, priv->define_id);
244 g_signal_handler_disconnect (priv->context, priv->end_id);
245
246 priv->start_id = 0;
247 priv->end_id = 0;
248 priv->define_id = 0;
249 }
250
251 if (priv->error_id)
252 {
253 g_signal_handler_disconnect (priv->context, priv->error_id);
254
255 priv->error_id = 0;
256 }
257
258 GDICT_NOTE (DEFBOX, "Removing old context");
259
260 g_object_unref (G_OBJECT (priv->context)((((GObject*) (void *) ((priv->context))))));
261 }
262
263 if (!context)
264 return;
265
266 if (!GDICT_IS_CONTEXT (context)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(context)); GType __t = ((gdict_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
267 {
268 g_warning ("Object of type '%s' instead of a GdictContext\n",
269 g_type_name (G_OBJECT_TYPE (context)(((((GTypeClass*) (((GTypeInstance*) (context))->g_class))
->g_type)))
));
270 return;
271 }
272
273 GDICT_NOTE (DEFBOX, "Setting new context");
274
275 priv->context = context;
276 g_object_ref (G_OBJECT (priv->context))((__typeof__ (((((GObject*) (void *) ((priv->context))))))
) (g_object_ref) (((((GObject*) (void *) ((priv->context))
)))))
;
277}
278
279static void
280gdict_defbox_set_property (GObject *object,
281 guint prop_id,
282 const GValue *value,
283 GParamSpec *pspec)
284{
285 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
286 GdictDefboxPrivate *priv = defbox->priv;
287
288 switch (prop_id)
289 {
290 case PROP_WORD:
291 gdict_defbox_lookup (defbox, g_value_get_string (value));
292 break;
293 case PROP_CONTEXT:
294 set_gdict_context (defbox, g_value_get_object (value));
295 break;
296 case PROP_DATABASE:
297 g_free (priv->database);
298 priv->database = g_strdup (g_value_get_string (value))g_strdup_inline (g_value_get_string (value));
299 break;
300 case PROP_FONT_NAME:
301 gdict_defbox_set_font_name (defbox, g_value_get_string (value));
302 break;
303 default:
304 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-defbox.c", 304, ("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)
;
305 break;
306 }
307}
308
309static void
310gdict_defbox_get_property (GObject *object,
311 guint prop_id,
312 GValue *value,
313 GParamSpec *pspec)
314{
315 GdictDefbox *defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
316 GdictDefboxPrivate *priv = defbox->priv;
317
318 switch (prop_id)
319 {
320 case PROP_WORD:
321 g_value_set_string (value, priv->word);
322 break;
323 case PROP_CONTEXT:
324 g_value_set_object (value, priv->context);
325 break;
326 case PROP_DATABASE:
327 g_value_set_string (value, priv->database);
328 break;
329 case PROP_FONT_NAME:
330 g_value_set_string (value, priv->font_name);
331 break;
332 default:
333 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-defbox.c", 333, ("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)
;
334 break;
335 }
336}
337
338/*
339 * this code has been copied from gtksourceview; it's the implementation
340 * for case-insensitive search in a GtkTextBuffer. this is non-trivial, as
341 * searches on a utf-8 text stream involve a norm(casefold(norm(utf8)))
342 * operation which can be costly on large buffers. luckily for us, it's
343 * not the case on a set of definitions.
344 */
345
346#define GTK_TEXT_UNKNOWN_CHAR0xFFFC 0xFFFC
347
348/* this function acts like g_utf8_offset_to_pointer() except that if it finds a
349 * decomposable character it consumes the decomposition length from the given
350 * offset. So it's useful when the offset was calculated for the normalized
351 * version of str, but we need a pointer to str itself. */
352static const gchar *
353pointer_from_offset_skipping_decomp (const gchar *str, gint offset)
354{
355 gchar *casefold, *normal;
356 const gchar *p, *q;
357
358 p = str;
359 while (offset > 0)
360 {
361 q = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
362 casefold = g_utf8_casefold (p, q - p);
363 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
364 offset -= g_utf8_strlen (normal, -1);
365 g_free (casefold);
366 g_free (normal);
367 p = q;
368 }
369 return p;
370}
371
372static gboolean
373exact_prefix_cmp (const gchar *string,
374 const gchar *prefix,
375 guint prefix_len)
376{
377 GUnicodeType type;
378
379 if (strncmp (string, prefix, prefix_len) != 0)
380 return FALSE(0);
381 if (string[prefix_len] == '\0')
382 return TRUE(!(0));
383
384 type = g_unichar_type (g_utf8_get_char (string + prefix_len));
385
386 /* If string contains prefix, check that prefix is not followed
387 * by a unicode mark symbol, e.g. that trailing 'a' in prefix
388 * is not part of two-char a-with-hat symbol in string. */
389 return type != G_UNICODE_SPACING_MARK &&
390 type != G_UNICODE_ENCLOSING_MARK &&
391 type != G_UNICODE_NON_SPACING_MARK;
392}
393
394static const gchar *
395utf8_strcasestr (const gchar *haystack, const gchar *needle)
396{
397 gsize needle_len;
398 gsize haystack_len;
399 const gchar *ret = NULL((void*)0);
400 gchar *p;
401 gchar *casefold;
402 gchar *caseless_haystack;
403 gint i;
404
405 g_return_val_if_fail (haystack != NULL, NULL)do{ (void)0; }while (0);
406 g_return_val_if_fail (needle != NULL, NULL)do{ (void)0; }while (0);
407
408 casefold = g_utf8_casefold (haystack, -1);
409 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
410 g_free (casefold);
411
412 needle_len = g_utf8_strlen (needle, -1);
413 haystack_len = g_utf8_strlen (caseless_haystack, -1);
414
415 if (needle_len == 0)
416 {
417 ret = (gchar *)haystack;
418 goto finally_1;
419 }
420
421 if (haystack_len < needle_len)
422 {
423 ret = NULL((void*)0);
424 goto finally_1;
425 }
426
427 p = (gchar*)caseless_haystack;
428 needle_len = strlen (needle);
429 i = 0;
430
431 while (*p)
432 {
433 if (exact_prefix_cmp (p, needle, needle_len))
434 {
435 ret = pointer_from_offset_skipping_decomp (haystack, i);
436 goto finally_1;
437 }
438
439 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
440 i++;
441 }
442
443finally_1:
444 g_free (caseless_haystack);
445
446 return ret;
447}
448
449static const gchar *
450utf8_strrcasestr (const gchar *haystack, const gchar *needle)
451{
452 gsize needle_len;
453 gsize haystack_len;
454 const gchar *ret = NULL((void*)0);
455 gchar *p;
456 gchar *casefold;
457 gchar *caseless_haystack;
458 gint i;
459
460 g_return_val_if_fail (haystack != NULL, NULL)do{ (void)0; }while (0);
461 g_return_val_if_fail (needle != NULL, NULL)do{ (void)0; }while (0);
462
463 casefold = g_utf8_casefold (haystack, -1);
464 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
465 g_free (casefold);
466
467 needle_len = g_utf8_strlen (needle, -1);
468 haystack_len = g_utf8_strlen (caseless_haystack, -1);
469
470 if (needle_len == 0)
471 {
472 ret = (gchar *)haystack;
473 goto finally_1;
474 }
475
476 if (haystack_len < needle_len)
477 {
478 ret = NULL((void*)0);
479 goto finally_1;
480 }
481
482 i = haystack_len - needle_len;
483 p = g_utf8_offset_to_pointer (caseless_haystack, i);
484 needle_len = strlen (needle);
485
486 while (p >= caseless_haystack)
487 {
488 if (exact_prefix_cmp (p, needle, needle_len))
489 {
490 ret = pointer_from_offset_skipping_decomp (haystack, i);
491 goto finally_1;
492 }
493
494 p = g_utf8_prev_char (p);
495 i--;
496 }
497
498finally_1:
499 g_free (caseless_haystack);
500
501 return ret;
502}
503
504static gboolean
505utf8_caselessnmatch (const char *s1, const char *s2,
506 gssize n1, gssize n2)
507{
508 gchar *casefold;
509 gchar *normalized_s1;
510 gchar *normalized_s2;
511 gint len_s1;
512 gint len_s2;
513 gboolean ret = FALSE(0);
514
515 g_return_val_if_fail (s1 != NULL, FALSE)do{ (void)0; }while (0);
516 g_return_val_if_fail (s2 != NULL, FALSE)do{ (void)0; }while (0);
517 g_return_val_if_fail (n1 > 0, FALSE)do{ (void)0; }while (0);
518 g_return_val_if_fail (n2 > 0, FALSE)do{ (void)0; }while (0);
519
520 casefold = g_utf8_casefold (s1, n1);
521 normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
522 g_free (casefold);
523
524 casefold = g_utf8_casefold (s2, n2);
525 normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
526 g_free (casefold);
527
528 len_s1 = strlen (normalized_s1);
529 len_s2 = strlen (normalized_s2);
530
531 if (len_s1 < len_s2)
532 goto finally_2;
533
534 ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
535
536finally_2:
537 g_free (normalized_s1);
538 g_free (normalized_s2);
539
540 return ret;
541}
542
543/* FIXME: total horror */
544static gboolean
545char_is_invisible (const GtkTextIter *iter)
546{
547 GSList *tags;
548 gboolean invisible = FALSE(0);
549 tags = gtk_text_iter_get_tags (iter);
550 while (tags)
551 {
552 gboolean this_invisible, invisible_set;
553 g_object_get (tags->data, "invisible", &this_invisible,
554 "invisible-set", &invisible_set, NULL((void*)0));
555 if (invisible_set)
556 invisible = this_invisible;
557 tags = g_slist_delete_link (tags, tags);
558 }
559 return invisible;
560}
561
562static void
563forward_chars_with_skipping (GtkTextIter *iter,
564 gint count,
565 gboolean skip_invisible,
566 gboolean skip_nontext,
567 gboolean skip_decomp)
568{
569 gint i;
570
571 g_return_if_fail (count >= 0)do{ (void)0; }while (0);
572
573 i = count;
574
575 while (i > 0)
576 {
577 gboolean ignored = FALSE(0);
578
579 /* minimal workaround to avoid the infinite loop of bug #168247.
580 * It doesn't fix the problemjust the symptom...
581 */
582 if (gtk_text_iter_is_end (iter))
583 return;
584
585 if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR0xFFFC)
586 ignored = TRUE(!(0));
587
588 /* FIXME: char_is_invisible() gets list of tags for each char there,
589 and checks every tag. It doesn't sound like a good idea. */
590 if (!ignored && skip_invisible && char_is_invisible (iter))
591 ignored = TRUE(!(0));
592
593 if (!ignored && skip_decomp)
594 {
595 /* being UTF8 correct sucks; this accounts for extra
596 offsets coming from canonical decompositions of
597 UTF8 characters (e.g. accented characters) which
598 g_utf8_normalize() performs */
599 gchar *normal;
600 gchar buffer[6];
601 gint buffer_len;
602
603 buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
604 normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD);
605 i -= (g_utf8_strlen (normal, -1) - 1);
606 g_free (normal);
607 }
608
609 gtk_text_iter_forward_char (iter);
610
611 if (!ignored)
612 --i;
613 }
614}
615
616static gboolean
617lines_match (const GtkTextIter *start,
618 const gchar **lines,
619 gboolean visible_only,
620 gboolean slice,
621 GtkTextIter *match_start,
622 GtkTextIter *match_end)
623{
624 GtkTextIter next;
625 gchar *line_text;
626 const gchar *found;
627 gint offset;
628
629 if (*lines == NULL((void*)0) || **lines == '\0')
630 {
631 if (match_start)
632 *match_start = *start;
633 if (match_end)
634 *match_end = *start;
635 return TRUE(!(0));
636 }
637
638 next = *start;
639 gtk_text_iter_forward_line (&next);
640
641 /* No more text in buffer, but *lines is nonempty */
642 if (gtk_text_iter_equal (start, &next))
643 return FALSE(0);
644
645 if (slice)
646 {
647 if (visible_only)
648 line_text = gtk_text_iter_get_visible_slice (start, &next);
649 else
650 line_text = gtk_text_iter_get_slice (start, &next);
651 }
652 else
653 {
654 if (visible_only)
655 line_text = gtk_text_iter_get_visible_text (start, &next);
656 else
657 line_text = gtk_text_iter_get_text (start, &next);
658 }
659
660 if (match_start) /* if this is the first line we're matching */
661 {
662 found = utf8_strcasestr (line_text, *lines);
663 }
664 else
665 {
666 /* If it's not the first line, we have to match from the
667 * start of the line.
668 */
669 if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
670 strlen (*lines)))
671 found = line_text;
672 else
673 found = NULL((void*)0);
674 }
675
676 if (found == NULL((void*)0))
677 {
678 g_free (line_text);
679 return FALSE(0);
680 }
681
682 /* Get offset to start of search string */
683 offset = g_utf8_strlen (line_text, found - line_text);
684
685 next = *start;
686
687 /* If match start needs to be returned, set it to the
688 * start of the search string.
689 */
690 forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE(0));
691 if (match_start)
692 {
693 *match_start = next;
694 }
695
696 /* Go to end of search string */
697 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE(!(0)));
698
699 g_free (line_text);
700
701 ++lines;
702
703 if (match_end)
704 *match_end = next;
705
706 /* pass NULL for match_start, since we don't need to find the
707 * start again.
708 */
709 return lines_match (&next, lines, visible_only, slice, NULL((void*)0), match_end);
710}
711
712static gboolean
713backward_lines_match (const GtkTextIter *start,
714 const gchar **lines,
715 gboolean visible_only,
716 gboolean slice,
717 GtkTextIter *match_start,
718 GtkTextIter *match_end)
719{
720 GtkTextIter line, next;
721 gchar *line_text;
722 const gchar *found;
723 gint offset;
724
725 if (*lines == NULL((void*)0) || **lines == '\0')
726 {
727 if (match_start)
728 *match_start = *start;
729 if (match_end)
730 *match_end = *start;
731 return TRUE(!(0));
732 }
733
734 line = next = *start;
735 if (gtk_text_iter_get_line_offset (&next) == 0)
736 {
737 if (!gtk_text_iter_backward_line (&next))
738 return FALSE(0);
739 }
740 else
741 gtk_text_iter_set_line_offset (&next, 0);
742
743 if (slice)
744 {
745 if (visible_only)
746 line_text = gtk_text_iter_get_visible_slice (&next, &line);
747 else
748 line_text = gtk_text_iter_get_slice (&next, &line);
749 }
750 else
751 {
752 if (visible_only)
753 line_text = gtk_text_iter_get_visible_text (&next, &line);
754 else
755 line_text = gtk_text_iter_get_text (&next, &line);
756 }
757
758 if (match_start) /* if this is the first line we're matching */
759 {
760 found = utf8_strrcasestr (line_text, *lines);
761 }
762 else
763 {
764 /* If it's not the first line, we have to match from the
765 * start of the line.
766 */
767 if (utf8_caselessnmatch (line_text, *lines, strlen (line_text),
768 strlen (*lines)))
769 found = line_text;
770 else
771 found = NULL((void*)0);
772 }
773
774 if (found == NULL((void*)0))
775 {
776 g_free (line_text);
777 return FALSE(0);
778 }
779
780 /* Get offset to start of search string */
781 offset = g_utf8_strlen (line_text, found - line_text);
782
783 forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE(0));
784
785 /* If match start needs to be returned, set it to the
786 * start of the search string.
787 */
788 if (match_start)
789 {
790 *match_start = next;
791 }
792
793 /* Go to end of search string */
794 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE(!(0)));
795
796 g_free (line_text);
797
798 ++lines;
799
800 if (match_end)
801 *match_end = next;
802
803 /* try to match the rest of the lines forward, passing NULL
804 * for match_start so lines_match will try to match the entire
805 * line */
806 return lines_match (&next, lines, visible_only,
807 slice, NULL((void*)0), match_end);
808}
809
810/* strsplit () that retains the delimiter as part of the string. */
811static gchar **
812breakup_string (const char *string,
813 const char *delimiter,
814 gint max_tokens)
815{
816 GSList *string_list = NULL((void*)0), *slist;
817 gchar **str_array, *s, *casefold, *new_string;
818 guint i, n = 1;
819
820 g_return_val_if_fail (string != NULL, NULL)do{ (void)0; }while (0);
13
Loop condition is false. Exiting loop
821 g_return_val_if_fail (delimiter != NULL, NULL)do{ (void)0; }while (0);
14
Loop condition is false. Exiting loop
822
823 if (max_tokens
14.1
'max_tokens' is < 1
< 1)
15
Taking true branch
824 max_tokens = G_MAXINT2147483647;
825
826 s = strstr (string, delimiter);
827 if (s)
16
Assuming 's' is null
17
Taking false branch
828 {
829 guint delimiter_len = strlen (delimiter);
830
831 do
832 {
833 guint len;
834
835 len = s - string + delimiter_len;
836 new_string = g_new (gchar, len + 1)((gchar *) g_malloc_n ((len + 1), sizeof (gchar)));
837 strncpy (new_string, string, len);
838 new_string[len] = 0;
839 casefold = g_utf8_casefold (new_string, -1);
840 g_free (new_string);
841 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
842 g_free (casefold);
843 string_list = g_slist_prepend (string_list, new_string);
844 n++;
845 string = s + delimiter_len;
846 s = strstr (string, delimiter);
847 } while (--max_tokens && s);
848 }
849
850 if (*string)
18
Taking true branch
851 {
852 n++;
853 casefold = g_utf8_casefold (string, -1);
854 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
855 g_free (casefold);
856 string_list = g_slist_prepend (string_list, new_string);
857 }
858
859 str_array = g_new (gchar*, n)((gchar* *) g_malloc_n ((n), sizeof (gchar*)));
860
861 i = n - 1;
862
863 str_array[i--] = NULL((void*)0);
864 for (slist = string_list; slist; slist = slist->next)
19
Loop condition is true. Entering loop body
20
Loop condition is true. Entering loop body
865 str_array[i--] = slist->data;
21
Out of bound memory access (access exceeds upper limit of memory block)
866
867 g_slist_free (string_list);
868
869 return str_array;
870}
871
872static gboolean
873gdict_defbox_iter_forward_search (const GtkTextIter *iter,
874 const gchar *str,
875 GtkTextIter *match_start,
876 GtkTextIter *match_end,
877 const GtkTextIter *limit)
878{
879 gchar **lines = NULL((void*)0);
880 GtkTextIter match;
881 gboolean retval = FALSE(0);
882 GtkTextIter search;
883
884 g_return_val_if_fail (iter != NULL, FALSE)do{ (void)0; }while (0);
9
Loop condition is false. Exiting loop
885 g_return_val_if_fail (str != NULL, FALSE)do{ (void)0; }while (0);
886
887 if (limit
9.1
'limit' is null
&& gtk_text_iter_compare (iter, limit) >= 0)
888 return FALSE(0);
889
890 if (*str == '\0')
10
Assuming the condition is false
11
Taking false branch
891 {
892 /* If we can move one char, return the empty string there */
893 match = *iter;
894
895 if (gtk_text_iter_forward_char (&match))
896 {
897 if (limit && gtk_text_iter_equal (&match, limit))
898 return FALSE(0);
899
900 if (match_start)
901 *match_start = match;
902
903 if (match_end)
904 *match_end = match;
905
906 return TRUE(!(0));
907 }
908 else
909 return FALSE(0);
910 }
911
912 /* locate all lines */
913 lines = breakup_string (str, "\n", -1);
12
Calling 'breakup_string'
914
915 search = *iter;
916
917 /* This loop has an inefficient worst-case, where
918 * gtk_text_iter_get_text () is called repeatedly on
919 * a single line.
920 */
921 do
922 {
923 GtkTextIter end;
924 gboolean res;
925
926 if (limit && gtk_text_iter_compare (&search, limit) >= 0)
927 break;
928
929 res = lines_match (&search, (const gchar**)lines,
930 TRUE(!(0)), FALSE(0),
931 &match, &end);
932 if (res)
933 {
934 if (limit == NULL((void*)0) ||
935 (limit && gtk_text_iter_compare (&end, limit) <= 0))
936 {
937 retval = TRUE(!(0));
938
939 if (match_start)
940 *match_start = match;
941
942 if (match_end)
943 *match_end = end;
944 }
945
946 break;
947 }
948 } while (gtk_text_iter_forward_line (&search));
949
950 g_strfreev ((gchar**) lines);
951
952 return retval;
953}
954
955static gboolean
956gdict_defbox_iter_backward_search (const GtkTextIter *iter,
957 const gchar *str,
958 GtkTextIter *match_start,
959 GtkTextIter *match_end,
960 const GtkTextIter *limit)
961{
962 gchar **lines = NULL((void*)0);
963 GtkTextIter match;
964 gboolean retval = FALSE(0);
965 GtkTextIter search;
966
967 g_return_val_if_fail (iter != NULL, FALSE)do{ (void)0; }while (0);
968 g_return_val_if_fail (str != NULL, FALSE)do{ (void)0; }while (0);
969
970 if (limit && gtk_text_iter_compare (iter, limit) <= 0)
971 return FALSE(0);
972
973 if (*str == '\0')
974 {
975 /* If we can move one char, return the empty string there */
976 match = *iter;
977
978 if (gtk_text_iter_backward_char (&match))
979 {
980 if (limit && gtk_text_iter_equal (&match, limit))
981 return FALSE(0);
982
983 if (match_start)
984 *match_start = match;
985
986 if (match_end)
987 *match_end = match;
988
989 return TRUE(!(0));
990 }
991 else
992 return FALSE(0);
993 }
994
995 /* locate all lines */
996 lines = breakup_string (str, "\n", -1);
997
998 search = *iter;
999
1000 /* This loop has an inefficient worst-case, where
1001 * gtk_text_iter_get_text () is called repeatedly on
1002 * a single line.
1003 */
1004 while (TRUE(!(0)))
1005 {
1006 GtkTextIter end;
1007 gboolean res;
1008
1009 if (limit && gtk_text_iter_compare (&search, limit) <= 0)
1010 break;
1011
1012 res = backward_lines_match (&search, (const gchar**)lines,
1013 TRUE(!(0)), FALSE(0),
1014 &match, &end);
1015 if (res)
1016 {
1017 if (limit == NULL((void*)0) ||
1018 (limit && gtk_text_iter_compare (&end, limit) > 0))
1019 {
1020 retval = TRUE(!(0));
1021
1022 if (match_start)
1023 *match_start = match;
1024
1025 if (match_end)
1026 *match_end = end;
1027
1028 }
1029
1030 break;
1031 }
1032
1033 if (gtk_text_iter_get_line_offset (&search) == 0)
1034 {
1035 if (!gtk_text_iter_backward_line (&search))
1036 break;
1037 }
1038 else
1039 gtk_text_iter_set_line_offset (&search, 0);
1040 }
1041
1042 g_strfreev ((gchar**) lines);
1043
1044 return retval;
1045}
1046
1047static gboolean
1048gdict_defbox_find_backward (GdictDefbox *defbox,
1049 const gchar *text)
1050{
1051 GdictDefboxPrivate *priv = defbox->priv;
1052 GtkTextIter start_iter, end_iter;
1053 GtkTextIter match_start, match_end;
1054 GtkTextIter iter;
1055 GtkTextMark *last_search;
1056 gboolean res;
1057
1058 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
1059
1060 gtk_text_buffer_get_bounds (priv->buffer, &start_iter, &end_iter);
1061
1062 /* if there already has been another result, begin from there */
1063 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-prev");
1064 if (last_search)
1065 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1066 else
1067 iter = end_iter;
1068
1069 res = gdict_defbox_iter_backward_search (&iter, text,
1070 &match_start, &match_end,
1071 NULL((void*)0));
1072 if (res)
1073 {
1074 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
1075 &match_start,
1076 0.0,
1077 TRUE(!(0)),
1078 0.0, 0.0);
1079 gtk_text_buffer_place_cursor (priv->buffer, &match_end);
1080 gtk_text_buffer_move_mark (priv->buffer,
1081 gtk_text_buffer_get_mark (priv->buffer, "selection_bound"),
1082 &match_start);
1083 gtk_text_buffer_create_mark (priv->buffer, "last-search-prev", &match_start, FALSE(0));
1084 gtk_text_buffer_create_mark (priv->buffer, "last-search-next", &match_end, FALSE(0));
1085
1086 return TRUE(!(0));
1087 }
1088
1089 return FALSE(0);
1090}
1091
1092static gboolean
1093hide_find_pane (gpointer user_data)
1094{
1095 GdictDefbox *defbox = user_data;
1096
1097 gtk_widget_hide (defbox->priv->find_pane);
1098 defbox->priv->show_find = FALSE(0);
1099
1100 gtk_widget_grab_focus (defbox->priv->text_view);
1101
1102 defbox->priv->hide_timeout = 0;
1103
1104 return FALSE(0);
1105}
1106
1107static void
1108find_prev_clicked_cb (GtkWidget *widget,
1109 gpointer user_data)
1110{
1111 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1112 GdictDefboxPrivate *priv = defbox->priv;
1113 const gchar *text;
1114 gboolean found;
1115
1116 gtk_widget_hide (priv->find_label);
1117
1118 text = gtk_entry_get_text (GTK_ENTRY (priv->find_entry)((((GtkEntry*) (void *) ((priv->find_entry))))));
1119 if (!text)
1120 return;
1121
1122 found = gdict_defbox_find_backward (defbox, text);
1123 if (!found)
1124 {
1125 gchar *str;
1126
1127 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1128 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1129 gtk_widget_show (priv->find_label);
1130
1131 g_free (str);
1132 }
1133
1134 if (priv->hide_timeout)
1135 {
1136 g_source_remove (priv->hide_timeout);
1137 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1138 }
1139}
1140
1141static gboolean
1142gdict_defbox_find_forward (GdictDefbox *defbox,
1143 const gchar *text,
1144 gboolean is_typing)
1145{
1146 GdictDefboxPrivate *priv = defbox->priv;
1147 GtkTextIter start_iter, end_iter;
1148 GtkTextIter match_start, match_end;
1149 GtkTextIter iter;
1150 GtkTextMark *last_search;
1151 gboolean res;
1152
1153 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
4
Loop condition is false. Exiting loop
1154
1155 gtk_text_buffer_get_bounds (priv->buffer, &start_iter, &end_iter);
1156
1157 if (!is_typing
4.1
'is_typing' is 1
)
5
Taking false branch
1158 {
1159 /* if there already has been another result, begin from there */
1160 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-next");
1161
1162 if (last_search)
1163 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1164 else
1165 iter = start_iter;
1166 }
1167 else
1168 {
1169 last_search = gtk_text_buffer_get_mark (priv->buffer, "last-search-prev");
1170
1171 if (last_search)
6
Assuming 'last_search' is null
7
Taking false branch
1172 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter, last_search);
1173 else
1174 iter = start_iter;
1175 }
1176
1177 res = gdict_defbox_iter_forward_search (&iter, text,
8
Calling 'gdict_defbox_iter_forward_search'
1178 &match_start,
1179 &match_end,
1180 NULL((void*)0));
1181 if (res)
1182 {
1183 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
1184 &match_start,
1185 0.0,
1186 TRUE(!(0)),
1187 0.0, 0.0);
1188 gtk_text_buffer_place_cursor (priv->buffer, &match_end);
1189 gtk_text_buffer_move_mark (priv->buffer,
1190 gtk_text_buffer_get_mark (priv->buffer, "selection_bound"),
1191 &match_start);
1192 gtk_text_buffer_create_mark (priv->buffer, "last-search-prev", &match_start, FALSE(0));
1193 gtk_text_buffer_create_mark (priv->buffer, "last-search-next", &match_end, FALSE(0));
1194
1195 return TRUE(!(0));
1196 }
1197
1198 return FALSE(0);
1199}
1200
1201static void
1202find_next_clicked_cb (GtkWidget *widget,
1203 gpointer user_data)
1204{
1205 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1206 GdictDefboxPrivate *priv = defbox->priv;
1207 const gchar *text;
1208 gboolean found;
1209
1210 gtk_widget_hide (priv->find_label);
1211
1212 text = gtk_entry_get_text (GTK_ENTRY (priv->find_entry)((((GtkEntry*) (void *) ((priv->find_entry))))));
1213 if (!text)
1214 return;
1215
1216 found = gdict_defbox_find_forward (defbox, text, FALSE(0));
1217 if (!found)
1218 {
1219 gchar *str;
1220
1221 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1222 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1223 gtk_widget_show (priv->find_label);
1224
1225 g_free (str);
1226 }
1227
1228 if (priv->hide_timeout)
1229 {
1230 g_source_remove (priv->hide_timeout);
1231 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1232 }
1233}
1234
1235static void
1236find_entry_changed_cb (GtkWidget *widget,
1237 gpointer user_data)
1238{
1239 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
1240 GdictDefboxPrivate *priv = defbox->priv;
1241 gchar *text;
1242 gboolean found;
1243
1244 gtk_widget_hide (priv->find_label);
1245
1246 text = gtk_editable_get_chars (GTK_EDITABLE (widget)((((GtkEditable*) (void *) ((widget))))), 0, -1);
1247 if (!text)
1
Assuming 'text' is non-null
2
Taking false branch
1248 return;
1249
1250 found = gdict_defbox_find_forward (defbox, text, TRUE(!(0)));
3
Calling 'gdict_defbox_find_forward'
1251 if (!found)
1252 {
1253 gchar *str;
1254
1255 str = g_strconcat (" <i>", _("Not found")((char *) g_dgettext ("mate-utils", "Not found")), "</i>", NULL((void*)0));
1256 gtk_label_set_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), str);
1257 gtk_widget_show (priv->find_label);
1258
1259 g_free (str);
1260 }
1261
1262 g_free (text);
1263
1264 if (priv->hide_timeout)
1265 {
1266 g_source_remove (priv->hide_timeout);
1267 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1268 }
1269}
1270
1271static void
1272close_button_clicked (GtkButton *button,
1273 gpointer data)
1274{
1275 GdictDefboxPrivate *priv = GDICT_DEFBOX (data)((((GdictDefbox*) (void *) ((data)))))->priv;
1276
1277 if (priv->hide_timeout)
1278 g_source_remove (priv->hide_timeout);
1279
1280 (void) hide_find_pane (data);
1281}
1282
1283static GtkWidget *
1284create_find_pane (GdictDefbox *defbox)
1285{
1286 GdictDefboxPrivate *priv;
1287 GtkWidget *find_pane;
1288 GtkWidget *label;
1289 GtkWidget *sep;
1290 GtkWidget *hbox1, *hbox2;
1291 GtkWidget *button;
1292
1293 priv = defbox->priv;
1294
1295 find_pane = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1296 gtk_container_set_border_width (GTK_CONTAINER (find_pane)((((GtkContainer*) (void *) ((find_pane))))), 0);
1297
1298 hbox1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1299 gtk_box_pack_start (GTK_BOX (find_pane)((((GtkBox*) (void *) ((find_pane))))), hbox1, TRUE(!(0)), TRUE(!(0)), 0);
1300 gtk_widget_show (hbox1);
1301
1302 button = gtk_button_new ();
1303 gtk_button_set_relief (GTK_BUTTON (button)((((GtkButton*) (void *) ((button))))), GTK_RELIEF_NONE);
1304 gtk_button_set_image (GTK_BUTTON (button)((((GtkButton*) (void *) ((button))))),
1305 gtk_image_new_from_icon_name ("window-close",
1306 GTK_ICON_SIZE_BUTTON));
1307 g_signal_connect (button, "clicked",g_signal_connect_data ((button), ("clicked"), (((GCallback) (
close_button_clicked))), (defbox), ((void*)0), (GConnectFlags
) 0)
1308 G_CALLBACK (close_button_clicked), defbox)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
close_button_clicked))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1309 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), button, FALSE(0), FALSE(0), 0);
1310 gtk_widget_show (button);
1311
1312 hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1313 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), hbox2, TRUE(!(0)), TRUE(!(0)), 0);
1314 gtk_widget_show (hbox2);
1315
1316 label = gtk_label_new_with_mnemonic (_("F_ind:")((char *) g_dgettext ("mate-utils", "F_ind:")));
1317 gtk_box_pack_start (GTK_BOX (hbox2)((((GtkBox*) (void *) ((hbox2))))), label, FALSE(0), FALSE(0), 0);
1318
1319 priv->find_entry = gtk_entry_new ();
1320 g_signal_connect (priv->find_entry, "changed",g_signal_connect_data ((priv->find_entry), ("changed"), ((
(GCallback) (find_entry_changed_cb))), (defbox), ((void*)0), (
GConnectFlags) 0)
1321 G_CALLBACK (find_entry_changed_cb), defbox)g_signal_connect_data ((priv->find_entry), ("changed"), ((
(GCallback) (find_entry_changed_cb))), (defbox), ((void*)0), (
GConnectFlags) 0)
;
1322 gtk_box_pack_start (GTK_BOX (hbox2)((((GtkBox*) (void *) ((hbox2))))), priv->find_entry, TRUE(!(0)), TRUE(!(0)), 0);
1323 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) ((label))))), priv->find_entry);
1324
1325 sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
1326 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), sep, FALSE(0), FALSE(0), 0);
1327 gtk_widget_show (sep);
1328
1329 priv->find_prev = gtk_button_new_with_mnemonic (_("_Previous")((char *) g_dgettext ("mate-utils", "_Previous")));
1330 gtk_button_set_image (GTK_BUTTON (priv->find_prev)((((GtkButton*) (void *) ((priv->find_prev))))),
1331 gtk_image_new_from_icon_name ("go-previous",
1332 GTK_ICON_SIZE_MENU));
1333 g_signal_connect (priv->find_prev, "clicked",g_signal_connect_data ((priv->find_prev), ("clicked"), (((
GCallback) (find_prev_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
1334 G_CALLBACK (find_prev_clicked_cb), defbox)g_signal_connect_data ((priv->find_prev), ("clicked"), (((
GCallback) (find_prev_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1335 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), priv->find_prev, FALSE(0), FALSE(0), 0);
1336
1337 priv->find_next = gtk_button_new_with_mnemonic (_("_Next")((char *) g_dgettext ("mate-utils", "_Next")));
1338 gtk_button_set_image (GTK_BUTTON (priv->find_next)((((GtkButton*) (void *) ((priv->find_next))))),
1339 gtk_image_new_from_icon_name ("go-next",
1340 GTK_ICON_SIZE_MENU));
1341 g_signal_connect (priv->find_next, "clicked",g_signal_connect_data ((priv->find_next), ("clicked"), (((
GCallback) (find_next_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
1342 G_CALLBACK (find_next_clicked_cb), defbox)g_signal_connect_data ((priv->find_next), ("clicked"), (((
GCallback) (find_next_clicked_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
1343 gtk_box_pack_start (GTK_BOX (hbox1)((((GtkBox*) (void *) ((hbox1))))), priv->find_next, FALSE(0), FALSE(0), 0);
1344
1345 priv->find_label = gtk_label_new (NULL((void*)0));
1346 gtk_label_set_use_markup (GTK_LABEL (priv->find_label)((((GtkLabel*) (void *) ((priv->find_label))))), TRUE(!(0)));
1347 gtk_box_pack_end (GTK_BOX (find_pane)((((GtkBox*) (void *) ((find_pane))))), priv->find_label, FALSE(0), FALSE(0), 0);
1348 gtk_widget_hide (priv->find_label);
1349
1350 return find_pane;
1351}
1352
1353static void
1354gdict_defbox_init_tags (GdictDefbox *defbox)
1355{
1356 GdictDefboxPrivate *priv = defbox->priv;
1357
1358 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
1359
1360 gtk_text_buffer_create_tag (priv->buffer, "italic",
1361 "style", PANGO_STYLE_ITALIC,
1362 NULL((void*)0));
1363 gtk_text_buffer_create_tag (priv->buffer, "bold",
1364 "weight", PANGO_WEIGHT_BOLD,
1365 NULL((void*)0));
1366 gtk_text_buffer_create_tag (priv->buffer, "underline",
1367 "underline", PANGO_UNDERLINE_SINGLE,
1368 NULL((void*)0));
1369
1370 gtk_text_buffer_create_tag (priv->buffer, "big",
1371 "scale", 1.6,
1372 NULL((void*)0));
1373 gtk_text_buffer_create_tag (priv->buffer, "small",
1374 "scale", PANGO_SCALE_SMALL((double)0.8333333333333),
1375 NULL((void*)0));
1376
1377 {
1378 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1379 gboolean prefer_dark = FALSE(0);
1380 GdkRGBA rgba;
1381
1382 /* HACK: we're hardcoding the Adwaita values because GtkTextTag
1383 * cannot be styled via CSS
1384 */
1385 g_object_get (settings, "gtk-application-prefer-dark-theme", &prefer_dark, NULL((void*)0));
1386
1387 if (!prefer_dark)
1388 gdk_rgba_parse (&rgba, "#2a76c6");
1389 else
1390 gdk_rgba_parse (&rgba, "#4a90d9");
1391
1392 priv->link_tag =
1393 gtk_text_buffer_create_tag (priv->buffer, "link",
1394 "underline", PANGO_UNDERLINE_SINGLE,
1395 "foreground-rgba", &rgba,
1396 NULL((void*)0));
1397
1398 if (!prefer_dark)
1399 gdk_rgba_parse (&rgba, "#215d9c");
1400 else
1401 gdk_rgba_parse (&rgba, "#2a76c6");
1402
1403 priv->visited_link_tag =
1404 gtk_text_buffer_create_tag (priv->buffer, "visited-link",
1405 "underline", PANGO_UNDERLINE_SINGLE,
1406 "foreground-rgba", &rgba,
1407 NULL((void*)0));
1408 }
1409
1410 gtk_text_buffer_create_tag (priv->buffer, "phonetic",
1411 "foreground", "dark gray",
1412 NULL((void*)0));
1413
1414 gtk_text_buffer_create_tag (priv->buffer, "query-title",
1415 "left-margin", QUERY_MARGIN48,
1416 "pixels-above-lines", 5,
1417 "pixels-below-lines", 20,
1418 NULL((void*)0));
1419 gtk_text_buffer_create_tag (priv->buffer, "query-from",
1420 "foreground", "dark gray",
1421 "scale", PANGO_SCALE_SMALL((double)0.8333333333333),
1422 "left-margin", QUERY_MARGIN48,
1423 "pixels-above-lines", 5,
1424 "pixels-below-lines", 10,
1425 NULL((void*)0));
1426
1427 gtk_text_buffer_create_tag (priv->buffer, "error-title",
1428 "foreground", "dark red",
1429 "left-margin", ERROR_MARGIN24,
1430 NULL((void*)0));
1431 gtk_text_buffer_create_tag (priv->buffer, "error-message",
1432 "left-margin", ERROR_MARGIN24,
1433 NULL((void*)0));
1434}
1435
1436static void
1437follow_if_is_link (GdictDefbox *defbox,
1438 GtkTextView *text_view,
1439 GtkTextIter *iter)
1440{
1441 GSList *tags, *l;
1442
1443 tags = gtk_text_iter_get_tags (iter);
1444
1445 for (l = tags; l != NULL((void*)0); l = l->next)
1446 {
1447 GtkTextTag *tag = l->data;
1448 gchar *name;
1449
1450 g_object_get (G_OBJECT (tag)((((GObject*) (void *) ((tag))))), "name", &name, NULL((void*)0));
1451 if (name &&
1452 (strcmp (name, "link") == 0 ||
1453 strcmp (name, "visited-link") == 0))
1454 {
1455 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
1456 GtkTextIter start, end;
1457 gchar *link_str;
1458
1459 start = *iter;
1460 end = *iter;
1461
1462 gtk_text_iter_backward_to_tag_toggle (&start, tag);
1463 gtk_text_iter_forward_to_tag_toggle (&end, tag);
1464
1465 link_str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
1466
1467 g_signal_emit (defbox, gdict_defbox_signals[LINK_CLICKED], 0, link_str);
1468
1469 g_free (link_str);
1470 g_free (name);
1471
1472 break;
1473 }
1474
1475 g_free (name);
1476 }
1477
1478 g_slist_free (tags);
1479}
1480
1481static gboolean
1482defbox_event_after_cb (GtkWidget *text_view,
1483 GdkEvent *event,
1484 GdictDefbox *defbox)
1485{
1486 GtkTextIter iter;
1487 GtkTextBuffer *buffer;
1488 GdkEventButton *button_event;
1489 gint bx, by;
1490
1491 if (event->type != GDK_BUTTON_RELEASE)
1492 return FALSE(0);
1493
1494 button_event = (GdkEventButton *) event;
1495
1496 if (button_event->button != 1)
1497 return FALSE(0);
1498
1499 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))));
1500 if (gtk_text_buffer_get_has_selection (buffer))
1501 return FALSE(0);
1502
1503 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1504 GTK_TEXT_WINDOW_WIDGET,
1505 button_event->x, button_event->y,
1506 &bx, &by);
1507
1508 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1509 &iter,
1510 bx, by);
1511
1512 follow_if_is_link (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), &iter);
1513
1514 return FALSE(0);
1515}
1516
1517static void
1518set_cursor_if_appropriate (GdictDefbox *defbox,
1519 GtkTextView *text_view,
1520 gint x,
1521 gint y)
1522{
1523 GdictDefboxPrivate *priv;
1524 GSList *tags, *l;
1525 GtkTextIter iter;
1526 gboolean hovering = FALSE(0);
1527
1528 priv = defbox->priv;
1529
1530 if (!priv->hand_cursor)
1531 {
1532 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1533 priv->hand_cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
1534 }
1535
1536 if (!priv->regular_cursor)
1537 {
1538 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
1539 priv->regular_cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
1540 }
1541
1542 gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
1543
1544 tags = gtk_text_iter_get_tags (&iter);
1545 for (l = tags; l != NULL((void*)0); l = l->next)
1546 {
1547 GtkTextTag *tag = l->data;
1548 gchar *name;
1549
1550 g_object_get (G_OBJECT (tag)((((GObject*) (void *) ((tag))))), "name", &name, NULL((void*)0));
1551 if (name &&
1552 (strcmp (name, "link") == 0 ||
1553 strcmp (name, "visited-link") == 0))
1554 {
1555 hovering = TRUE(!(0));
1556 g_free (name);
1557
1558 break;
1559 }
1560
1561 g_free (name);
1562 }
1563
1564 if (hovering != defbox->priv->is_hovering)
1565 {
1566 defbox->priv->is_hovering = (hovering != FALSE(0));
1567
1568 if (defbox->priv->is_hovering)
1569 gdk_window_set_cursor (gtk_text_view_get_window (text_view,
1570 GTK_TEXT_WINDOW_TEXT),
1571 defbox->priv->hand_cursor);
1572 else
1573 gdk_window_set_cursor (gtk_text_view_get_window (text_view,
1574 GTK_TEXT_WINDOW_TEXT),
1575 defbox->priv->regular_cursor);
1576 }
1577
1578 if (tags)
1579 g_slist_free (tags);
1580}
1581
1582static gboolean
1583defbox_motion_notify_cb (GtkWidget *text_view,
1584 GdkEventMotion *event,
1585 GdictDefbox *defbox)
1586{
1587 gint bx, by;
1588
1589 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1590 GTK_TEXT_WINDOW_WIDGET,
1591 event->x, event->y,
1592 &bx, &by);
1593
1594 set_cursor_if_appropriate (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), bx, by);
1595
1596 return FALSE(0);
1597}
1598
1599static gboolean
1600defbox_visibility_notify_cb (GtkWidget *text_view,
1601 GdkEventVisibility *event,
1602 GdictDefbox *defbox)
1603{
1604 GdkDisplay *display;
1605 GdkSeat *seat;
1606 GdkDevice *pointer;
1607 gint wx, wy;
1608 gint bx, by;
1609
1610 display = gdk_window_get_display (event->window);
1611 seat = gdk_display_get_default_seat (display);
1612 pointer = gdk_seat_get_pointer (seat);
1613 gdk_window_get_device_position (gtk_widget_get_window (text_view), pointer, &wx, &wy, NULL((void*)0));
1614
1615 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))),
1616 GTK_TEXT_WINDOW_WIDGET,
1617 wx, wy,
1618 &bx, &by);
1619
1620 set_cursor_if_appropriate (defbox, GTK_TEXT_VIEW (text_view)((((GtkTextView*) (void *) ((text_view))))), bx, by);
1621
1622 return FALSE(0);
1623}
1624
1625static GObject *
1626gdict_defbox_constructor (GType type,
1627 guint n_construct_properties,
1628 GObjectConstructParam *construct_params)
1629{
1630 GdictDefbox *defbox;
1631 GdictDefboxPrivate *priv;
1632 GObject *object;
1633 GtkWidget *sw;
1634
1635 object = G_OBJECT_CLASS (gdict_defbox_parent_class)((((GObjectClass*) (void *) ((gdict_defbox_parent_class)))))->constructor (type,
1636 n_construct_properties,
1637 construct_params);
1638 defbox = GDICT_DEFBOX (object)((((GdictDefbox*) (void *) ((object)))));
1639 priv = defbox->priv;
1640
1641 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
1642 gtk_widget_set_vexpand (sw, TRUE(!(0)));
1643 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) ((sw))))),
1644 GTK_POLICY_AUTOMATIC,
1645 GTK_POLICY_AUTOMATIC);
1646 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) ((sw))))),
1647 GTK_SHADOW_IN);
1648 gtk_box_pack_start (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), sw, TRUE(!(0)), TRUE(!(0)), 0);
1649 gtk_widget_show (sw);
1650
1651 priv->buffer = gtk_text_buffer_new (NULL((void*)0));
1652 gdict_defbox_init_tags (defbox);
1653
1654 priv->text_view = gtk_text_view_new_with_buffer (priv->buffer);
1655 gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))), FALSE(0));
1656 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))), 4);
1657 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) ((sw))))), priv->text_view);
1658 gtk_widget_show (priv->text_view);
1659
1660 priv->find_pane = create_find_pane (defbox);
1661 gtk_box_pack_end (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), priv->find_pane, FALSE(0), FALSE(0), 0);
1662
1663 /* stuff to make the link machinery work */
1664 g_signal_connect (priv->text_view, "event-after",g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
1665 G_CALLBACK (defbox_event_after_cb),g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
1666 defbox)g_signal_connect_data ((priv->text_view), ("event-after"),
(((GCallback) (defbox_event_after_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
;
1667 g_signal_connect (priv->text_view, "motion-notify-event",g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
1668 G_CALLBACK (defbox_motion_notify_cb),g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
1669 defbox)g_signal_connect_data ((priv->text_view), ("motion-notify-event"
), (((GCallback) (defbox_motion_notify_cb))), (defbox), ((void
*)0), (GConnectFlags) 0)
;
1670 g_signal_connect (priv->text_view, "visibility-notify-event",g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
1671 G_CALLBACK (defbox_visibility_notify_cb),g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
1672 defbox)g_signal_connect_data ((priv->text_view), ("visibility-notify-event"
), (((GCallback) (defbox_visibility_notify_cb))), (defbox), (
(void*)0), (GConnectFlags) 0)
;
1673
1674 return object;
1675}
1676
1677/* we override the GtkWidget::show_all method since we have widgets
1678 * we don't want to show, such as the find pane
1679 */
1680static void
1681gdict_defbox_show_all (GtkWidget *widget)
1682{
1683 GdictDefbox *defbox = GDICT_DEFBOX (widget)((((GdictDefbox*) (void *) ((widget)))));
1684 GdictDefboxPrivate *priv = defbox->priv;
1685
1686 gtk_widget_show (widget);
1687
1688 if (priv->show_find)
1689 gtk_widget_show_all (priv->find_pane);
1690}
1691
1692static void
1693gdict_defbox_real_show_find (GdictDefbox *defbox)
1694{
1695 gtk_widget_show_all (defbox->priv->find_pane);
1696 defbox->priv->show_find = TRUE(!(0));
1697
1698 gtk_widget_grab_focus (defbox->priv->find_entry);
1699
1700 defbox->priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
1701}
1702
1703static void
1704gdict_defbox_real_find_next (GdictDefbox *defbox)
1705{
1706 /* synthetize a "clicked" signal to the "next" button */
1707 gtk_button_clicked (GTK_BUTTON (defbox->priv->find_next)((((GtkButton*) (void *) ((defbox->priv->find_next))))));
1708}
1709
1710static void
1711gdict_defbox_real_find_previous (GdictDefbox *defbox)
1712{
1713 /* synthetize a "clicked" signal to the "prev" button */
1714 gtk_button_clicked (GTK_BUTTON (defbox->priv->find_prev)((((GtkButton*) (void *) ((defbox->priv->find_prev))))));
1715}
1716
1717static void
1718gdict_defbox_real_hide_find (GdictDefbox *defbox)
1719{
1720 gtk_widget_hide (defbox->priv->find_pane);
1721 defbox->priv->show_find = FALSE(0);
1722
1723 gtk_widget_grab_focus (defbox->priv->text_view);
1724
1725 if (defbox->priv->hide_timeout)
1726 {
1727 g_source_remove (defbox->priv->hide_timeout);
1728 defbox->priv->hide_timeout = 0;
1729 }
1730}
1731
1732static void
1733gdict_defbox_class_init (GdictDefboxClass *klass)
1734{
1735 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
1736 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass)((((GtkWidgetClass*) (void *) ((klass)))));
1737 GtkBindingSet *binding_set;
1738
1739 gobject_class->constructor = gdict_defbox_constructor;
1740 gobject_class->set_property = gdict_defbox_set_property;
1741 gobject_class->get_property = gdict_defbox_get_property;
1742 gobject_class->dispose = gdict_defbox_dispose;
1743 gobject_class->finalize = gdict_defbox_finalize;
1744
1745 widget_class->show_all = gdict_defbox_show_all;
1746
1747 /**
1748 * GdictDefbox:word:
1749 *
1750 * The word to look up.
1751 *
1752 * Since: 0.10
1753 */
1754 g_object_class_install_property (gobject_class,
1755 PROP_WORD,
1756 g_param_spec_string ("word",
1757 "Word",
1758 "The word to look up",
1759 NULL((void*)0),
1760 G_PARAM_READWRITE));
1761 /**
1762 * GdictDefbox:context:
1763 *
1764 * The #GdictContext object used to get the word definition.
1765 *
1766 * Since: 0.1
1767 */
1768 g_object_class_install_property (gobject_class,
1769 PROP_CONTEXT,
1770 g_param_spec_object ("context",
1771 "Context",
1772 "The GdictContext object used to get the word definition",
1773 GDICT_TYPE_CONTEXT(gdict_context_get_type ()),
1774 (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)));
1775 /**
1776 * GdictDefbox:database
1777 *
1778 * The database used by the #GdictDefbox bound to this object to get the word
1779 * definition.
1780 *
1781 * Since: 0.1
1782 */
1783 g_object_class_install_property (gobject_class,
1784 PROP_DATABASE,
1785 g_param_spec_string ("database",
1786 "Database",
1787 "The database used to query the GdictContext",
1788 GDICT_DEFAULT_DATABASE"*",
1789 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1790 /**
1791 * GdictDefbox:font-name
1792 *
1793 * The name of the font used by the #GdictDefbox to display the definitions.
1794 * use the same string you use for pango_font_description_from_string().
1795 *
1796 * Since: 0.3
1797 */
1798 g_object_class_install_property (gobject_class,
1799 PROP_FONT_NAME,
1800 g_param_spec_string ("font-name",
1801 "Font Name",
1802 "The font to be used by the defbox",
1803 GDICT_DEFAULT_FONT_NAME"Sans 10",
1804 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1805
1806 gdict_defbox_signals[SHOW_FIND] =
1807 g_signal_new ("show-find",
1808 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1809 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1810 G_STRUCT_OFFSET (GdictDefboxClass, show_find)((glong) __builtin_offsetof(GdictDefboxClass, show_find)),
1811 NULL((void*)0), NULL((void*)0),
1812 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1813 G_TYPE_NONE((GType) ((1) << (2))), 0);
1814 gdict_defbox_signals[FIND_PREVIOUS] =
1815 g_signal_new ("find-previous",
1816 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1817 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1818 G_STRUCT_OFFSET (GdictDefboxClass, find_previous)((glong) __builtin_offsetof(GdictDefboxClass, find_previous)),
1819 NULL((void*)0), NULL((void*)0),
1820 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1821 G_TYPE_NONE((GType) ((1) << (2))), 0);
1822 gdict_defbox_signals[FIND_NEXT] =
1823 g_signal_new ("find-next",
1824 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1825 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1826 G_STRUCT_OFFSET (GdictDefboxClass, find_next)((glong) __builtin_offsetof(GdictDefboxClass, find_next)),
1827 NULL((void*)0), NULL((void*)0),
1828 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1829 G_TYPE_NONE((GType) ((1) << (2))), 0);
1830 gdict_defbox_signals[HIDE_FIND] =
1831 g_signal_new ("hide-find",
1832 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1833 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1834 G_STRUCT_OFFSET (GdictDefboxClass, hide_find)((glong) __builtin_offsetof(GdictDefboxClass, hide_find)),
1835 NULL((void*)0), NULL((void*)0),
1836 gdict_marshal_VOID__VOIDg_cclosure_marshal_VOID__VOID,
1837 G_TYPE_NONE((GType) ((1) << (2))), 0);
1838 gdict_defbox_signals[LINK_CLICKED] =
1839 g_signal_new ("link-clicked",
1840 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1841 G_SIGNAL_RUN_LAST,
1842 G_STRUCT_OFFSET (GdictDefboxClass, link_clicked)((glong) __builtin_offsetof(GdictDefboxClass, link_clicked)),
1843 NULL((void*)0), NULL((void*)0),
1844 gdict_marshal_VOID__STRINGg_cclosure_marshal_VOID__STRING,
1845 G_TYPE_NONE((GType) ((1) << (2))), 1,
1846 G_TYPE_STRING((GType) ((16) << (2))));
1847
1848 klass->show_find = gdict_defbox_real_show_find;
1849 klass->hide_find = gdict_defbox_real_hide_find;
1850 klass->find_next = gdict_defbox_real_find_next;
1851 klass->find_previous = gdict_defbox_real_find_previous;
1852
1853 binding_set = gtk_binding_set_by_class (klass);
1854 gtk_binding_entry_add_signal (binding_set,
1855 GDK_KEY_f0x066, GDK_CONTROL_MASK,
1856 "show-find",
1857 0);
1858 gtk_binding_entry_add_signal (binding_set,
1859 GDK_KEY_g0x067, GDK_CONTROL_MASK,
1860 "find-next",
1861 0);
1862 gtk_binding_entry_add_signal (binding_set,
1863 GDK_KEY_g0x067, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1864 "find-previous",
1865 0);
1866 gtk_binding_entry_add_signal (binding_set,
1867 GDK_KEY_Escape0xff1b, 0,
1868 "hide-find",
1869 0);
1870}
1871
1872static void
1873gdict_defbox_init (GdictDefbox *defbox)
1874{
1875 GdictDefboxPrivate *priv;
1876
1877 gtk_orientable_set_orientation (GTK_ORIENTABLE (defbox)((((GtkOrientable*) (void *) ((defbox))))), GTK_ORIENTATION_VERTICAL);
1878 gtk_box_set_spacing (GTK_BOX (defbox)((((GtkBox*) (void *) ((defbox))))), 6);
1879
1880 priv = gdict_defbox_get_instance_private (defbox);
1881 defbox->priv = priv;
1882
1883 priv->context = NULL((void*)0);
1884 priv->database = g_strdup (GDICT_DEFAULT_DATABASE)g_strdup_inline ("*");
1885 priv->font_name = g_strdup (GDICT_DEFAULT_FONT_NAME)g_strdup_inline ("Sans 10");
1886 priv->word = NULL((void*)0);
1887
1888 priv->definitions = NULL((void*)0);
1889
1890 priv->busy_cursor = NULL((void*)0);
1891 priv->hand_cursor = NULL((void*)0);
1892 priv->regular_cursor = NULL((void*)0);
1893
1894 priv->show_find = FALSE(0);
1895 priv->is_searching = FALSE(0);
1896 priv->is_hovering = FALSE(0);
1897
1898 priv->hide_timeout = 0;
1899}
1900
1901/**
1902 * gdict_defbox_new:
1903 *
1904 * Creates a new #GdictDefbox widget. Use this widget to search for
1905 * a word using a #GdictContext, and to show the resulting definition(s).
1906 * You must set a #GdictContext for this widget using
1907 * gdict_defbox_set_context().
1908 *
1909 * Return value: a new #GdictDefbox widget.
1910 *
1911 * Since: 0.1
1912 */
1913GtkWidget *
1914gdict_defbox_new (void)
1915{
1916 return g_object_new (GDICT_TYPE_DEFBOX(gdict_defbox_get_type ()), NULL((void*)0));
1917}
1918
1919/**
1920 * gdict_defbox_new_with_context:
1921 * @context: a #GdictContext
1922 *
1923 * Creates a new #GdictDefbox widget. Use this widget to search for
1924 * a word using @context, and to show the resulting definition.
1925 *
1926 * Return value: a new #GdictDefbox widget.
1927 *
1928 * Since: 0.1
1929 */
1930GtkWidget *
1931gdict_defbox_new_with_context (GdictContext *context)
1932{
1933 g_return_val_if_fail (GDICT_IS_CONTEXT (context), NULL)do{ (void)0; }while (0);
1934
1935 return g_object_new (GDICT_TYPE_DEFBOX(gdict_defbox_get_type ()), "context", context, NULL((void*)0));
1936}
1937
1938/**
1939 * gdict_defbox_set_context:
1940 * @defbox: a #GdictDefbox
1941 * @context: a #GdictContext
1942 *
1943 * Sets @context as the #GdictContext to be used by @defbox in order
1944 * to retrieve the definitions of a word.
1945 *
1946 * Since: 0.1
1947 */
1948void
1949gdict_defbox_set_context (GdictDefbox *defbox,
1950 GdictContext *context)
1951{
1952 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
1953 g_return_if_fail (context == NULL || GDICT_IS_CONTEXT (context))do{ (void)0; }while (0);
1954
1955 g_object_set (defbox, "context", context, NULL((void*)0));
1956}
1957
1958/**
1959 * gdict_defbox_get_context:
1960 * @defbox: a #GdictDefbox
1961 *
1962 * Gets the #GdictContext used by @defbox.
1963 *
1964 * Return value: a #GdictContext.
1965 *
1966 * Since: 0.1
1967 */
1968GdictContext *
1969gdict_defbox_get_context (GdictDefbox *defbox)
1970{
1971 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
1972
1973 return defbox->priv->context;
1974}
1975
1976/**
1977 * gdict_defbox_set_database:
1978 * @defbox: a #GdictDefbox
1979 * @database: a database
1980 *
1981 * Sets @database as the database used by the #GdictContext bound to @defbox
1982 * to query for word definitions.
1983 *
1984 * Since: 0.1
1985 */
1986void
1987gdict_defbox_set_database (GdictDefbox *defbox,
1988 const gchar *database)
1989{
1990 GdictDefboxPrivate *priv;
1991
1992 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
1993
1994 priv = defbox->priv;
1995
1996 g_free (priv->database);
1997 priv->database = g_strdup (database)g_strdup_inline (database);
1998
1999 g_object_notify (G_OBJECT (defbox)((((GObject*) (void *) ((defbox))))), "database");
2000}
2001
2002/**
2003 * gdict_defbox_get_database:
2004 * @defbox: a #GdictDefbox
2005 *
2006 * Gets the database used by @defbox. See gdict_defbox_set_database().
2007 *
2008 * Return value: the name of a database. The return string is owned by
2009 * the #GdictDefbox widget and should not be modified or freed.
2010 *
2011 * Since: 0.1
2012 */
2013const gchar *
2014gdict_defbox_get_database (GdictDefbox *defbox)
2015{
2016 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2017
2018 return defbox->priv->database;
2019}
2020
2021/**
2022 * gdict_defbox_get_word:
2023 * @defbox: a #GdictDefbox
2024 *
2025 * Retrieves the word being looked up.
2026 *
2027 * Return value: the word looked up, or %NULL. The returned string is
2028 * owned by the #GdictDefbox widget and should never be modified or
2029 * freed.
2030 *
2031 * Since: 0.12
2032 */
2033const gchar *
2034gdict_defbox_get_word (GdictDefbox *defbox)
2035{
2036 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2037
2038 return defbox->priv->word;
2039}
2040
2041/**
2042 * gdict_defbox_set_show_find:
2043 * @defbox: a #GdictDefbox
2044 * @show_find: %TRUE to show the find pane
2045 *
2046 * Whether @defbox should show the find pane.
2047 *
2048 * Since: 0.1
2049 */
2050void
2051gdict_defbox_set_show_find (GdictDefbox *defbox,
2052 gboolean show_find)
2053{
2054 GdictDefboxPrivate *priv;
2055
2056 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2057
2058 priv = defbox->priv;
2059
2060 if (priv->show_find == show_find)
2061 return;
2062
2063 priv->show_find = (show_find != FALSE(0));
2064 if (priv->show_find)
2065 {
2066 gtk_widget_show_all (priv->find_pane);
2067 gtk_widget_grab_focus (priv->find_entry);
2068
2069 if (!priv->hide_timeout)
2070 priv->hide_timeout = g_timeout_add_seconds (5, hide_find_pane, defbox);
2071 }
2072 else
2073 {
2074 gtk_widget_hide (priv->find_pane);
2075
2076 if (priv->hide_timeout)
2077 {
2078 g_source_remove (priv->hide_timeout);
2079 priv->hide_timeout = 0;
2080 }
2081 }
2082}
2083
2084/**
2085 * gdict_defbox_get_show_find:
2086 * @defbox: a #GdictDefbox
2087 *
2088 * Gets whether the find pane should be visible or not.
2089 *
2090 * Return value: %TRUE if the find pane is visible.
2091 *
2092 * Since: 0.1
2093 */
2094gboolean
2095gdict_defbox_get_show_find (GdictDefbox *defbox)
2096{
2097 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), FALSE)do{ (void)0; }while (0);
2098
2099 return (defbox->priv->show_find == TRUE(!(0)));
2100}
2101
2102static void
2103lookup_start_cb (GdictContext *context,
2104 gpointer user_data)
2105{
2106 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2107 GdictDefboxPrivate *priv = defbox->priv;
2108 GdkWindow *window;
2109
2110 priv->is_searching = TRUE(!(0));
2111
2112 if (!priv->busy_cursor)
2113 {
2114 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))));
2115 priv->busy_cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
2116 }
2117
2118 window = gtk_text_view_get_window (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2119 GTK_TEXT_WINDOW_WIDGET);
2120
2121 gdk_window_set_cursor (window, priv->busy_cursor);
2122}
2123
2124static void
2125lookup_end_cb (GdictContext *context,
2126 gpointer user_data)
2127{
2128 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2129 GdictDefboxPrivate *priv = defbox->priv;
2130 GtkTextBuffer *buffer;
2131 GtkTextIter start;
2132 GdkWindow *window;
2133
2134 /* explicitely move the cursor to the beginning */
2135 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2136 gtk_text_buffer_get_start_iter (buffer, &start);
2137 gtk_text_buffer_place_cursor (buffer, &start);
2138
2139 window = gtk_text_view_get_window (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2140 GTK_TEXT_WINDOW_WIDGET);
2141
2142 gdk_window_set_cursor (window, NULL((void*)0));
2143
2144 priv->is_searching = FALSE(0);
2145}
2146
2147static void
2148gdict_defbox_insert_word (GdictDefbox *defbox,
2149 GtkTextIter *iter,
2150 const gchar *word)
2151{
2152 GdictDefboxPrivate *priv;
2153 gchar *text;
2154
2155 if (!word)
2156 return;
2157
2158 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2159 priv = defbox->priv;
2160
2161 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2162
2163 text = g_strdup_printf ("%s\n", word);
2164 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2165 iter,
2166 text, strlen (text),
2167 "big", "bold", "query-title",
2168 NULL((void*)0));
2169 g_free (text);
2170}
2171
2172/* escape a link string; links are expressed as "{...}".
2173 * the link with the '{}' removed is stored inside link_str, while
2174 * the returned value is a pointer to what follows the trailing '}'.
2175 * link_str is allocated and should be freed.
2176 */
2177static const gchar *
2178escape_link (const gchar *str,
2179 gchar **link_str)
2180{
2181 gsize str_len;
2182 GString *link_buf;
2183 const gchar *p;
2184
2185 str_len = strlen (str);
2186 link_buf = g_string_sized_new (str_len - 2);
2187
2188 for (p = str + 1; *p != '}'; p++)
2189 {
2190 link_buf = g_string_append_c (link_buf, *p)g_string_append_c_inline (link_buf, *p);
2191 }
2192
2193 if (link_str)
2194 *link_str = g_string_free (link_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((link_buf
), ((0))) : g_string_free_and_steal (link_buf)) : (g_string_free
) ((link_buf), ((0))))
;
2195
2196 p++;
2197
2198 return p;
2199}
2200
2201static const gchar *
2202escape_phonethic (const gchar *str,
2203 gchar **phon_str)
2204{
2205 gsize str_len;
2206 GString *phon_buf;
2207 const gchar *p;
2208
2209 str_len = strlen (str);
2210 phon_buf = g_string_sized_new (str_len - 2);
2211
2212 for (p = str + 1; *p != '\\'; p++)
2213 {
2214 phon_buf = g_string_append_c (phon_buf, *p)g_string_append_c_inline (phon_buf, *p);
2215 }
2216
2217 if (phon_str)
2218 *phon_str = g_string_free (phon_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((phon_buf
), ((0))) : g_string_free_and_steal (phon_buf)) : (g_string_free
) ((phon_buf), ((0))))
;
2219
2220 p++;
2221
2222 return p;
2223}
2224
2225static void
2226gdict_defbox_insert_body (GdictDefbox *defbox,
2227 GtkTextIter *iter,
2228 const gchar *body)
2229{
2230 GdictDefboxPrivate *priv;
2231 gchar **words;
2232 gint len, i;
2233 GtkTextIter end_iter;
2234
2235 if (!body)
2236 return;
2237
2238 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2239 priv = defbox->priv;
2240
2241 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2242
2243 words = g_strsplit (body, " ", -1);
2244 len = g_strv_length (words);
2245 end_iter = *iter;
2246
2247 for (i = 0; i < len; i++)
2248 {
2249 gchar *w = words[i];
2250 gint w_len = strlen (w);
2251 gchar *begin, *end;
2252
2253 if (w_len == 0)
2254 continue;
2255
2256 begin = g_utf8_offset_to_pointer (w, 0);
2257
2258 if (*begin == '{')
2259 {
2260 end = g_utf8_strrchr (w, -1, '}');
2261
2262 /* see this is a self contained link */
2263 if (end && *end == '}')
2264 {
2265 const gchar *rest;
2266 gchar *link_str;
2267
2268 rest = escape_link (w, &link_str);
2269
2270 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2271 &end_iter,
2272 link_str, -1,
2273 "link",
2274 NULL((void*)0));
2275
2276 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2277
2278 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2279 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2280
2281 g_free (link_str);
2282
2283 continue;
2284 }
2285 else
2286 {
2287 /* uh-oh: the link ends in another word */
2288 GString *buf;
2289 gchar *next;
2290 gint cur = i;
2291
2292 buf = g_string_new (NULL((void*)0));
2293 next = words[cur++];
2294
2295 while (next && (end = g_utf8_strrchr (next, -1, '}')) == NULL((void*)0))
2296 {
2297 buf = g_string_append (buf, next)(__builtin_constant_p (next) ? __extension__ ({ const char * const
__val = (next); g_string_append_len_inline (buf, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (buf, next, (gssize) -
1))
;
2298 buf = g_string_append_c (buf, ' ')g_string_append_c_inline (buf, ' ');
2299
2300 next = words[cur++];
2301 }
2302
2303 buf = g_string_append (buf, next)(__builtin_constant_p (next) ? __extension__ ({ const char * const
__val = (next); g_string_append_len_inline (buf, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (buf, next, (gssize) -
1))
;
2304
2305 next = g_string_free (buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((buf)
, ((0))) : g_string_free_and_steal (buf)) : (g_string_free) (
(buf), ((0))))
;
2306
2307 if (end && *end == '}')
2308 {
2309 const gchar *rest;
2310 gchar *link_str;
2311
2312 rest = escape_link (next, &link_str);
2313
2314 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2315 &end_iter,
2316 link_str, -1,
2317 "link",
2318 NULL((void*)0));
2319
2320 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2321 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2322
2323 g_free (link_str);
2324 }
2325
2326 g_free (next);
2327 i = cur;
2328
2329 continue;
2330 }
2331 }
2332 else if (*begin == '\\')
2333 {
2334 end = g_utf8_strrchr (w, -1, '\\');
2335
2336 if (end && *end == '\\')
2337 {
2338 const gchar *rest;
2339 gchar *phon;
2340
2341 rest = escape_phonethic (w, &phon);
2342
2343 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2344 &end_iter,
2345 phon, -1,
2346 "italic", "phonetic",
2347 NULL((void*)0));
2348
2349 gtk_text_buffer_insert (priv->buffer, &end_iter, rest, -1);
2350
2351 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2352 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", -1);
2353
2354 g_free (phon);
2355
2356 continue;
2357 }
2358 }
2359
2360 gtk_text_buffer_insert (priv->buffer, &end_iter, w, w_len);
2361
2362 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2363 gtk_text_buffer_insert (priv->buffer, &end_iter, " ", 1);
2364 }
2365
2366 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
2367 gtk_text_buffer_insert (priv->buffer, &end_iter, "\n", 1);
2368
2369 *iter = end_iter;
2370
2371 g_strfreev (words);
2372}
2373
2374static void
2375gdict_defbox_insert_from (GdictDefbox *defbox,
2376 GtkTextIter *iter,
2377 const gchar *database)
2378{
2379 GdictDefboxPrivate *priv;
2380 gchar *text;
2381
2382 if (!database)
2383 return;
2384
2385 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2386 priv = defbox->priv;
2387
2388 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2389
2390 text = g_strdup_printf ("\t-- From %s\n\n", database);
2391 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2392 iter,
2393 text, strlen (text),
2394 "small", "query-from",
2395 NULL((void*)0));
2396 g_free (text);
2397}
2398
2399static void
2400gdict_defbox_insert_error (GdictDefbox *defbox,
2401 GtkTextIter *iter,
2402 const gchar *title,
2403 const gchar *message)
2404{
2405 GdictDefboxPrivate *priv;
2406 GtkTextMark *mark;
2407 GtkTextIter cur_iter;
2408
2409 if (!title)
2410 return;
2411
2412 g_assert (GDICT_IS_DEFBOX (defbox))do { (void) 0; } while (0);
2413 priv = defbox->priv;
2414
2415 g_assert (GTK_IS_TEXT_BUFFER (priv->buffer))do { (void) 0; } while (0);
2416
2417 mark = gtk_text_buffer_create_mark (priv->buffer, "block-cursor", iter, FALSE(0));
2418 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2419
2420 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2421 &cur_iter,
2422 title, strlen (title),
2423 "error-title", "big", "bold",
2424 NULL((void*)0));
2425 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2426
2427 gtk_text_buffer_insert (priv->buffer, &cur_iter, "\n\n", -1);
2428 gtk_text_buffer_get_iter_at_mark (priv->buffer, &cur_iter, mark);
2429
2430 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
2431 &cur_iter,
2432 message, strlen (message),
2433 "error-message",
2434 NULL((void*)0));
2435}
2436
2437static void
2438definition_found_cb (GdictContext *context,
2439 GdictDefinition *definition,
2440 gpointer user_data)
2441{
2442 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2443 GdictDefboxPrivate *priv = defbox->priv;
2444 GtkTextIter iter;
2445 Definition *def;
2446
2447 /* insert the word if this is the first definition */
2448 if (!priv->definitions)
2449 {
2450 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2451 gdict_defbox_insert_word (defbox, &iter,
2452 gdict_definition_get_word (definition));
2453 }
2454
2455 def = definition_new ();
2456
2457 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
2458 def->begin = gtk_text_iter_get_offset (&iter);
2459 gdict_defbox_insert_body (defbox, &iter, gdict_definition_get_text (definition));
2460
2461 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
2462 gdict_defbox_insert_from (defbox, &iter, gdict_definition_get_database (definition));
2463
2464 def->definition = gdict_definition_ref (definition);
2465
2466 priv->definitions = g_slist_append (priv->definitions, def);
2467}
2468
2469static void
2470error_cb (GdictContext *context,
2471 const GError *error,
2472 gpointer user_data)
2473{
2474 GdictDefbox *defbox = GDICT_DEFBOX (user_data)((((GdictDefbox*) (void *) ((user_data)))));
2475 GdictDefboxPrivate *priv = defbox->priv;
2476 GtkTextIter iter;
2477
2478 if (!error)
2479 return;
2480
2481 gdict_defbox_clear (defbox);
2482
2483 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2484 gdict_defbox_insert_error (defbox, &iter,
2485 _("Error while looking up definition")((char *) g_dgettext ("mate-utils", "Error while looking up definition"
))
,
2486 error->message);
2487
2488 g_free (priv->word);
2489 priv->word = NULL((void*)0);
2490
2491 defbox->priv->is_searching = FALSE(0);
2492}
2493
2494/**
2495 * gdict_defbox_lookup:
2496 * @defbox: a #GdictDefbox
2497 * @word: the word to look up
2498 *
2499 * Searches @word inside the dictionary sources using the #GdictContext
2500 * provided when creating @defbox or set using gdict_defbox_set_context().
2501 *
2502 * Since: 0.1
2503 */
2504void
2505gdict_defbox_lookup (GdictDefbox *defbox,
2506 const gchar *word)
2507{
2508 GdictDefboxPrivate *priv;
2509 GError *define_error;
2510
2511 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2512
2513 priv = defbox->priv;
2514
2515 if (!priv->context)
2516 {
2517 g_warning ("Attempting to look up `%s', but no GdictContext "
2518 "has been set. Use gdict_defbox_set_context() "
2519 "before invoking gdict_defbox_lookup().",
2520 word);
2521 return;
2522 }
2523
2524 if (priv->is_searching)
2525 {
2526 _gdict_show_error_dialog (GTK_WIDGET (defbox)((((GtkWidget*) (void *) ((defbox))))),
2527 _("Another search is in progress")((char *) g_dgettext ("mate-utils", "Another search is in progress"
))
,
2528 _("Please wait until the current search ends.")((char *) g_dgettext ("mate-utils", "Please wait until the current search ends."
))
);
2529
2530 return;
2531 }
2532
2533 gdict_defbox_clear (defbox);
2534
2535 if (!priv->start_id)
2536 {
2537 priv->start_id = g_signal_connect (priv->context, "lookup-start",g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2538 G_CALLBACK (lookup_start_cb),g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2539 defbox)g_signal_connect_data ((priv->context), ("lookup-start"), (
((GCallback) (lookup_start_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
2540 priv->define_id = g_signal_connect (priv->context, "definition-found",g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
2541 G_CALLBACK (definition_found_cb),g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
2542 defbox)g_signal_connect_data ((priv->context), ("definition-found"
), (((GCallback) (definition_found_cb))), (defbox), ((void*)0
), (GConnectFlags) 0)
;
2543 priv->end_id = g_signal_connect (priv->context, "lookup-end",g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2544 G_CALLBACK (lookup_end_cb),g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
2545 defbox)g_signal_connect_data ((priv->context), ("lookup-end"), ((
(GCallback) (lookup_end_cb))), (defbox), ((void*)0), (GConnectFlags
) 0)
;
2546 }
2547
2548 if (!priv->error_id)
2549 priv->error_id = g_signal_connect (priv->context, "error",g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
2550 G_CALLBACK (error_cb),g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
2551 defbox)g_signal_connect_data ((priv->context), ("error"), (((GCallback
) (error_cb))), (defbox), ((void*)0), (GConnectFlags) 0)
;
2552
2553 g_free (priv->word);
2554 priv->word = g_strdup (word)g_strdup_inline (word);
2555 g_object_notify (G_OBJECT (defbox)((((GObject*) (void *) ((defbox))))), "word");
2556
2557 define_error = NULL((void*)0);
2558 gdict_context_define_word (priv->context,
2559 priv->database,
2560 word,
2561 &define_error);
2562 if (define_error)
2563 {
2564 GtkTextIter iter;
2565
2566 gtk_text_buffer_get_start_iter (priv->buffer, &iter);
2567 gdict_defbox_insert_error (defbox, &iter,
2568 _("Error while retrieving the definition")((char *) g_dgettext ("mate-utils", "Error while retrieving the definition"
))
,
2569 define_error->message);
2570
2571 g_error_free (define_error);
2572 }
2573}
2574
2575/**
2576 * gdict_defbox_clear:
2577 * @defbox: a @GdictDefbox
2578 *
2579 * Clears the buffer of @defbox
2580 *
2581 * Since: 0.1
2582 */
2583void
2584gdict_defbox_clear (GdictDefbox *defbox)
2585{
2586 GdictDefboxPrivate *priv;
2587 GtkTextIter start, end;
2588
2589 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2590
2591 priv = defbox->priv;
2592
2593 /* destroy previously found definitions */
2594 if (priv->definitions)
2595 {
2596 g_slist_free_full (priv->definitions, (GDestroyNotify) definition_free);
2597 priv->definitions = NULL((void*)0);
2598 }
2599
2600 gtk_text_buffer_get_bounds (priv->buffer, &start, &end);
2601 gtk_text_buffer_delete (priv->buffer, &start, &end);
2602}
2603
2604/**
2605 * gdict_defbox_find_next:
2606 * @defbox: a #GdictDefbox
2607 *
2608 * Emits the "find-next" signal.
2609 *
2610 * Since: 0.1
2611 */
2612void
2613gdict_defbox_find_next (GdictDefbox *defbox)
2614{
2615 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2616
2617 g_signal_emit (defbox, gdict_defbox_signals[FIND_NEXT], 0);
2618}
2619
2620/**
2621 * gdict_defbox_find_previous:
2622 * @defbox: a #GdictDefbox
2623 *
2624 * Emits the "find-previous" signal.
2625 *
2626 * Since: 0.1
2627 */
2628void
2629gdict_defbox_find_previous (GdictDefbox *defbox)
2630{
2631 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2632
2633 g_signal_emit (defbox, gdict_defbox_signals[FIND_PREVIOUS], 0);
2634}
2635
2636/**
2637 * gdict_defbox_select_all:
2638 * @defbox: a #GdictDefbox
2639 *
2640 * Selects all the text displayed by @defbox
2641 *
2642 * Since: 0.1
2643 */
2644void
2645gdict_defbox_select_all (GdictDefbox *defbox)
2646{
2647 GdictDefboxPrivate *priv;
2648 GtkTextBuffer *buffer;
2649 GtkTextIter start, end;
2650
2651 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2652
2653 priv = defbox->priv;
2654 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2655
2656 gtk_text_buffer_get_bounds (buffer, &start, &end);
2657 gtk_text_buffer_select_range (buffer, &start, &end);
2658}
2659
2660/**
2661 * gdict_defbox_copy_to_clipboard:
2662 * @defbox: a #GdictDefbox
2663 * @clipboard: a #GtkClipboard
2664 *
2665 * Copies the selected text inside @defbox into @clipboard.
2666 *
2667 * Since: 0.1
2668 */
2669void
2670gdict_defbox_copy_to_clipboard (GdictDefbox *defbox,
2671 GtkClipboard *clipboard)
2672{
2673 GdictDefboxPrivate *priv;
2674 GtkTextBuffer *buffer;
2675
2676 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2677 g_return_if_fail (GTK_IS_CLIPBOARD (clipboard))do{ (void)0; }while (0);
2678
2679 priv = defbox->priv;
2680 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2681
2682 gtk_text_buffer_copy_clipboard (buffer, clipboard);
2683}
2684
2685/**
2686 * gdict_defbox_count_definitions:
2687 * @defbox: a #GdictDefbox
2688 *
2689 * Gets the number of definitions displayed by @defbox
2690 *
2691 * Return value: the number of definitions.
2692 *
2693 * Since: 0.1
2694 */
2695gint
2696gdict_defbox_count_definitions (GdictDefbox *defbox)
2697{
2698 GdictDefboxPrivate *priv;
2699
2700 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), -1)do{ (void)0; }while (0);
2701
2702 priv = defbox->priv;
2703 if (!priv->definitions)
2704 return -1;
2705
2706 return g_slist_length (priv->definitions);
2707}
2708
2709/**
2710 * gdict_defbox_jump_to_definition:
2711 * @defbox: a #GdictDefbox
2712 * @number: the definition to jump to
2713 *
2714 * Scrolls to the definition identified by @number. If @number is -1,
2715 * jumps to the last definition.
2716 *
2717 * Since: 0.1
2718 */
2719void
2720gdict_defbox_jump_to_definition (GdictDefbox *defbox,
2721 gint number)
2722{
2723 GdictDefboxPrivate *priv;
2724 gint count;
2725 Definition *def;
2726 GtkTextBuffer *buffer;
2727 GtkTextIter def_start;
2728
2729 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2730
2731 count = gdict_defbox_count_definitions (defbox) - 1;
2732 if (count == -1)
2733 return;
2734
2735 if ((number == -1) || (number > count))
2736 number = count;
2737
2738 priv = defbox->priv;
2739 def = (Definition *) g_slist_nth_data (priv->definitions, number);
2740 if (!def)
2741 return;
2742
2743 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2744 gtk_text_buffer_get_iter_at_offset (buffer, &def_start, def->begin);
2745 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))),
2746 &def_start,
2747 0.0,
2748 TRUE(!(0)),
2749 0.0, 0.0);
2750}
2751
2752/**
2753 * gdict_defbox_get_text:
2754 * @defbox: a #GdictDefbox
2755 * @length: return location for the text length or %NULL
2756 *
2757 * Gets the full contents of @defbox.
2758 *
2759 * Return value: a newly allocated string containing the text displayed by
2760 * @defbox.
2761 *
2762 * Since: 0.1
2763 */
2764gchar *
2765gdict_defbox_get_text (GdictDefbox *defbox,
2766 gsize *length)
2767{
2768 GdictDefboxPrivate *priv;
2769 GtkTextBuffer *buffer;
2770 GtkTextIter start, end;
2771 gchar *retval;
2772
2773 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2774
2775 priv = defbox->priv;
2776 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2777
2778 gtk_text_buffer_get_bounds (buffer, &start, &end);
2779
2780 retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
2781
2782 if (length)
2783 *length = strlen (retval);
2784
2785 return retval;
2786}
2787
2788/**
2789 * gdict_defbox_set_font_name:
2790 * @defbox: a #GdictDefbox
2791 * @font_name: a font description, or %NULL
2792 *
2793 * Sets @font_name as the font for @defbox. It calls internally
2794 * pango_font_description_from_string() and gtk_widget_modify_font().
2795 *
2796 * Passing %NULL for @font_name will reset any previously set font.
2797 *
2798 * Since: 0.3.0
2799 */
2800void
2801gdict_defbox_set_font_name (GdictDefbox *defbox,
2802 const gchar *font_name)
2803{
2804 GdictDefboxPrivate *priv;
2805 PangoFontDescription *font_desc;
2806
2807 g_return_if_fail (GDICT_IS_DEFBOX (defbox))do{ (void)0; }while (0);
2808
2809 priv = defbox->priv;
2810
2811 if (font_name)
2812 {
2813 font_desc = pango_font_description_from_string (font_name);
2814 g_return_if_fail (font_desc != NULL)do{ (void)0; }while (0);
2815 }
2816 else
2817 font_desc = NULL((void*)0);
2818
2819 gtk_widget_override_font (priv->text_view, font_desc);
2820
2821 if (font_desc)
2822 pango_font_description_free (font_desc);
2823
2824 g_free (priv->font_name);
2825 priv->font_name = g_strdup (font_name)g_strdup_inline (font_name);
2826}
2827
2828/**
2829 * gdict_defbox_get_font_name:
2830 * @defbox: a #GdictDefbox
2831 *
2832 * Retrieves the font currently used by @defbox.
2833 *
2834 * Return value: a font name. The returned string is owned by @defbox and
2835 * should not be modified or freed.
2836 *
2837 * Since: 0.3
2838 */
2839const gchar *
2840gdict_defbox_get_font_name (GdictDefbox *defbox)
2841{
2842 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2843
2844 return defbox->priv->font_name;
2845}
2846
2847/**
2848 * gdict_defbox_get_selected_word:
2849 * @defbox: a #GdictDefbox
2850 *
2851 * Retrieves the selected word from the defbox widget
2852 *
2853 * Return value: a newly allocated string containing the selected
2854 * word. Use g_free() when done using it.
2855 *
2856 * Since: 0.12
2857 */
2858gchar *
2859gdict_defbox_get_selected_word (GdictDefbox *defbox)
2860{
2861 GdictDefboxPrivate *priv;
2862 GtkTextBuffer *buffer;
2863
2864 g_return_val_if_fail (GDICT_IS_DEFBOX (defbox), NULL)do{ (void)0; }while (0);
2865
2866 priv = defbox->priv;
2867 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view)((((GtkTextView*) (void *) ((priv->text_view))))));
2868
2869 if (!gtk_text_buffer_get_has_selection (buffer))
2870 return NULL((void*)0);
2871 else
2872 {
2873 GtkTextIter start, end;
2874 gchar *retval;
2875
2876 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
2877 retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
2878
2879 return retval;
2880 }
2881}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ee3f8f.html b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ee3f8f.html new file mode 100644 index 00000000..727c588a --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/report-ee3f8f.html @@ -0,0 +1,954 @@ + + + +screenshot-save.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:mate-screenshot/src/screenshot-save.c
Warning:line 227, column 17
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name screenshot-save.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 static -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/mate-screenshot/src -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I . -I . -D MATELOCALEDIR="/usr/local/share/locale" -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -D _REENTRANT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-4 -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/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -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/lib64/dbus-1.0/include -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/mate-screenshot/src -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-09-19-105706-7102-1 -x c screenshot-save.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* Copyright (C) 2001-2006 Jonathan Blandford <jrb@alum.mit.edu>
2 * Copyright (C) 2012-2021 MATE Developers
3 *
4 * This file is part of MATE Utils.
5 *
6 * MATE Utils 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MATE Utils 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with MATE Utils. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H1
21#include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <unistd.h>
26#include <errno(*__errno_location ()).h>
27#include <signal.h>
28#include <string.h>
29#include <glib/gi18n.h>
30
31#include "screenshot-save.h"
32
33static char *parent_dir = NULL((void*)0);
34static char *tmp_filename = NULL((void*)0);
35
36static SaveFunction save_callback = NULL((void*)0);
37static gpointer save_user_data = NULL((void*)0);
38
39/* Strategy for saving:
40 *
41 * We keep another process around to handle saving the image. This is
42 * done for two reasons. One, the saving takes a non-zero amount of
43 * time (about a quarter of a second on my box.) This will make it
44 * more interactive. The second reason is to make the child
45 * responsible for cleaning up the temp dir. If the parent process is
46 * killed or segfaults, the child process can clean up the temp dir.
47 */
48static void
49clean_up_temporary_dir (gboolean gui_on_error)
50{
51 char *message;
52 gboolean error_occurred = FALSE(0);
53 if (g_file_test (tmp_filename, G_FILE_TEST_EXISTS))
54 error_occurred = unlink (tmp_filename);
55 if (g_file_test (parent_dir, G_FILE_TEST_EXISTS))
56 error_occurred = rmdir (parent_dir) || error_occurred;
57
58 if (error_occurred)
59 {
60 message = g_strdup_printf (_("Unable to clear the temporary folder:\n%s")gettext ("Unable to clear the temporary folder:\n%s"),
61 tmp_filename);
62 if (gui_on_error)
63 {
64 GtkWidget *dialog;
65
66 dialog = gtk_message_dialog_new (NULL((void*)0), 0,
67 GTK_MESSAGE_ERROR,
68 GTK_BUTTONS_OK,
69 "%s", message);
70 gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
71 gtk_widget_destroy (dialog);
72 }
73 else
74 {
75 g_warning ("%s", message);
76 }
77 g_free (message);
78 }
79 g_free (tmp_filename);
80 g_free (parent_dir);
81}
82
83static void
84child_done_notification (GPid pid,
85 gint status,
86 gpointer data)
87{
88 /* This should never be called. */
89
90 /* We expect the child to die after the parent. If the child dies
91 * than it either segfaulted, or was randomly killed. In either
92 * case, we can't reasonably continue. */
93 GtkWidget *dialog;
94
95 dialog = gtk_message_dialog_new (NULL((void*)0), 0,
96 GTK_MESSAGE_ERROR,
97 GTK_BUTTONS_OK,
98 _("The child save process unexpectedly exited. We are unable to write the screenshot to disk.")gettext ("The child save process unexpectedly exited. We are unable to write the screenshot to disk."
)
);
99 gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
100 gtk_widget_destroy (dialog);
101
102 clean_up_temporary_dir (TRUE(!(0)));
103
104 exit (1);
105}
106
107static gboolean
108read_pipe_from_child (GIOChannel *source,
109 GIOCondition condition,
110 gpointer data)
111{
112 if (condition & G_IO_IN)
113 {
114 gchar *message = NULL((void*)0);
115 gchar *error_message = NULL((void*)0);
116 GtkWidget *dialog;
117 GIOStatus status;
118
119 status = g_io_channel_read_line (source, &error_message, NULL((void*)0), NULL((void*)0), NULL((void*)0));
120
121 if (status == G_IO_STATUS_NORMAL)
122 {
123 message = g_strdup_printf ("Unable to save the screenshot to disk:\n\n%s", error_message);
124 dialog = gtk_message_dialog_new (NULL((void*)0), 0,
125 GTK_MESSAGE_ERROR,
126 GTK_BUTTONS_OK,
127 "%s", message);
128 gtk_dialog_run (GTK_DIALOG (dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
129 gtk_widget_destroy (dialog);
130 exit (1);
131 }
132 }
133
134 (*save_callback) (save_user_data);
135
136 return FALSE(0);
137}
138
139static char *
140make_temp_directory (void)
141{
142 gint result, i;
143 gchar *dir_name;
144
145 i = 0;
146 do
147 {
148 gchar *tmp_dir = g_strdup_printf ("mate-screenshot.%u.%d",
149 (unsigned int) getpid (),
150 i++);
151
152 dir_name = g_build_filename (g_get_tmp_dir (),
153 tmp_dir,
154 NULL((void*)0));
155 g_free (tmp_dir);
156
157 result = g_mkdir_with_parents (dir_name, 0777);
158 if (result < 0)
159 {
160 g_free (dir_name);
161
162 if (errno(*__errno_location ()) != EEXIST17)
163 return NULL((void*)0);
164 else
165 continue;
166 }
167 else
168 return dir_name;
169 }
170 while (TRUE(!(0)));
171}
172
173static void
174signal_handler (int sig)
175{
176 clean_up_temporary_dir (FALSE(0));
177
178 signal (sig, SIG_DFL((__sighandler_t) 0));
179 kill (getpid (), sig);
180}
181
182void
183screenshot_save_start (GdkPixbuf *pixbuf,
184 SaveFunction callback,
185 gpointer user_data)
186{
187 GPid pid;
188 int parent_exit_notification[2];
189 int pipe_from_child[2];
190
191 if (pipe (parent_exit_notification) == -1)
192 perror("pipe error");
193
194 if (pipe (pipe_from_child) == -1)
195 perror("pipe error");
196
197 parent_dir = make_temp_directory ();
198 if (parent_dir == NULL((void*)0))
199 return;
200
201 tmp_filename = g_build_filename (parent_dir,
202 _("Screenshot.png")gettext ("Screenshot.png"),
203 NULL((void*)0));
204 save_callback = callback;
205 save_user_data = user_data;
206
207 pid = fork ();
208 if (pid == 0)
209 {
210 GError *error = NULL((void*)0);
211 char c;
212
213 signal (SIGINT2, signal_handler);
214 signal (SIGTERM15, signal_handler);
215
216 close (parent_exit_notification [1]);
217 close (pipe_from_child [0]);
218
219 if (! gdk_pixbuf_save (pixbuf, tmp_filename,
220 "png", &error,
221 "tEXt::Software", "mate-screenshot",
222 NULL((void*)0)))
223 {
224 if (error && error->message)
225 {
226 if (write (pipe_from_child[1], error->message, strlen (error->message)) == -1)
227 perror("write error");
This statement is never executed
228 }
229 else
230 {
231#define ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk") _("Unknown error saving screenshot to disk")gettext ("Unknown error saving screenshot to disk")
232 if (write (pipe_from_child[1], ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk"), strlen (ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk"))) == -1)
233 perror("write error");
234 }
235 }
236 /* By closing the pipe, we let the main process know that we're
237 * done saving it. */
238 close (pipe_from_child[1]);
239
240 if (read (parent_exit_notification[0], &c, 1) == -1)
241 perror("read error");
242
243 clean_up_temporary_dir (FALSE(0));
244 _exit (0);
245 }
246 else if (pid > 0)
247 {
248 GIOChannel *channel;
249
250 close (parent_exit_notification[0]);
251 close (pipe_from_child[1]);
252
253 channel = g_io_channel_unix_new (pipe_from_child[0]);
254 g_io_add_watch (channel,
255 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
256 read_pipe_from_child,
257 NULL((void*)0));
258 g_io_channel_unref (channel);
259 g_child_watch_add (pid, child_done_notification, NULL((void*)0));
260 }
261 else
262 /* George awesomely wrote code originally to handle the
263 * could-not-fork case synchronously. I'm not copying it, as I'm
264 * guessing that the system is pretty hosed if that's the case.
265 * However, he gets major kudos for trying. (-:
266 */
267 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "screenshot-save.c"
, 267, ((const char*) (__func__)), ((void*)0)); } while (0)
;
268}
269
270const char *
271screenshot_save_get_filename (void)
272{
273 return tmp_filename;
274}
diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/scanview.css b/2023-09-19-105706-7102-1@63a29bff1e50_master/scanview.css new file mode 100644 index 00000000..cf8a5a6a --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2023-09-19-105706-7102-1@63a29bff1e50_master/sorttable.js b/2023-09-19-105706-7102-1@63a29bff1e50_master/sorttable.js new file mode 100644 index 00000000..32faa078 --- /dev/null +++ b/2023-09-19-105706-7102-1@63a29bff1e50_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write("