~ubuntu-branches/ubuntu/karmic/gtk-gnutella/karmic

« back to all changes in this revision

Viewing changes to src/ui/gtk/drop.c

  • Committer: Bazaar Package Importer
  • Author(s): Anand Kumria
  • Date: 2005-08-04 11:32:05 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050804113205-q746i4lgo3rtlegn
Tags: 0.95.4-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: drop.c,v 1.9 2005/06/25 01:37:44 daichik Exp $
 
3
 *
 
4
 * Copyright (c) 2004, Christian Biere
 
5
 *
 
6
 *----------------------------------------------------------------------
 
7
 * This file is part of gtk-gnutella.
 
8
 *
 
9
 *  gtk-gnutella is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  (at your option) any later version.
 
13
 *
 
14
 *  gtk-gnutella is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with gtk-gnutella; if not, write to the Free Software
 
21
 *  Foundation, Inc.:
 
22
 *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 *----------------------------------------------------------------------
 
24
 */
 
25
 
 
26
/**
 
27
 * @ingroup gtk
 
28
 * @file
 
29
 *
 
30
 * Drop support - no dragging, just dropping.
 
31
 *
 
32
 * @author Christian Biere
 
33
 * @date 2004
 
34
 */
 
35
 
 
36
#include "gui.h"
 
37
 
 
38
#ifdef USE_GTK2
 
39
 
 
40
RCSID("$Id: drop.c,v 1.9 2005/06/25 01:37:44 daichik Exp $");
 
41
 
 
42
#include "drop.h"
 
43
#include "statusbar.h"
 
44
#include "search.h"
 
45
 
 
46
#include "if/bridge/ui2c.h"
 
47
#include "if/core/downloads.h"          /* URN_INDEX */
 
48
#include "if/core/guid.h"                       /* blank_guid[] */
 
49
#include "if/gui_property_priv.h"
 
50
 
 
51
#include "lib/glib-missing.h"
 
52
#include "lib/url.h"
 
53
#include "lib/urn.h"
 
54
#include "lib/override.h"               /* Must be the last header included */
 
55
 
 
56
/*
 
57
 * Private prototypes;
 
58
 */
 
59
 
 
60
static gboolean handle_not_implemented(gchar *url);
 
61
static gboolean handle_magnet(gchar *url);
 
62
 
 
63
/*
 
64
 * Private data
 
65
 */
 
66
 
 
67
static GtkClipboard *cb;
 
68
 
 
69
static const struct {
 
70
        const char * const proto;
 
71
        gboolean (* handler)(gchar *url);
 
72
} proto_handlers[] = {
 
73
        { "http",       handle_not_implemented },
 
74
        { "ftp",        handle_not_implemented },
 
75
        { "magnet",     handle_magnet },
 
76
};
 
77
 
 
78
/*
 
79
 * Private functions
 
80
 */
 
81
 
 
82
static gboolean
 
83
handle_not_implemented(gchar *unused_url)
 
84
{
 
85
        (void) unused_url;
 
86
 
 
87
        statusbar_gui_warning(10,
 
88
                        _("Support for this protocol is not yet implemented"));
 
89
        return FALSE;
 
90
}
 
91
 
 
92
static void
 
93
plus_to_space(gchar *s)
 
94
{
 
95
        gint c;
 
96
        gchar *p;
 
97
 
 
98
        for (p = s; (c = *p) != '\0'; p++)
 
99
                if (c == '+')
 
100
                        *p = ' ';
 
101
}
 
102
 
 
103
static gboolean
 
104
handle_magnet(gchar *url)
 
105
{
 
106
        gchar *p, *q, *next;
 
107
        struct {
 
108
                gboolean ready;
 
109
                gchar *file;
 
110
                guint32 ip;
 
111
                guint16 port;
 
112
                gchar *hostname;
 
113
                gchar *sha1;
 
114
        } dl = { FALSE, NULL, 0, 0, NULL, NULL };
 
115
 
 
116
        p = strchr(url, ':');
 
117
        g_assert(p);
 
118
        p++;
 
119
 
 
120
        if (*p != '?') {
 
121
                g_message("Invalid MAGNET URI");
 
122
                return FALSE;
 
123
        }
 
124
        p++;
 
125
 
 
126
        for (/* NOTHING */; p; p = next) {
 
127
                const gchar *name;
 
128
 
 
129
                q = strchr(p, '=');
 
130
                if (!q || p == q) {
 
131
                        g_message("Invalid MAGNET URI");
 
132
                        return FALSE;
 
133
                }
 
134
                name = p;
 
135
                g_assert((ssize_t) (q - p) > 0);
 
136
 
 
137
                *q++ = '\0';    /* Overwrite '=' and skip to next character */
 
138
                next = strchr(q, '&');
 
139
                if (next) {
 
140
                        *next++ = '\0';
 
141
                        if (*next == '\0')
 
142
                                next = NULL;
 
143
                }
 
144
                plus_to_space(q);
 
145
                if (!url_unescape(q, TRUE)) {
 
146
                        g_message("Invalidly encoded MAGNET URI");
 
147
                        return FALSE;
 
148
                }
 
149
 
 
150
                /* q points to the value; p is free to use */
 
151
 
 
152
                if (0 == strcmp(name, "dn")) {
 
153
                        /* Descriptive Name */
 
154
                        dl.file = q;
 
155
                } else if (0 == strcmp(name, "xs")) {
 
156
                        /* eXact Source */
 
157
                        static const char n2r_query[] = "/uri-res/N2R?";
 
158
                        static const char http_prefix[] = "http://";
 
159
                        gchar *hash;
 
160
                        gchar digest[SHA1_RAW_SIZE];
 
161
                        guint32 addr;
 
162
                        guint16 port;
 
163
                        gchar *hostname = NULL;
 
164
                        gchar *ep;
 
165
 
 
166
                        /* XXX: This should be handled elsewhere e.g., downloads.c in
 
167
                         *              a generic way. */
 
168
 
 
169
                        if (dl.ready) {
 
170
                                /* TODO:
 
171
                                 *                      Alternatives sources should be used
 
172
                                 */
 
173
                                g_message("More than one source; skipping");
 
174
                                continue;
 
175
                        }
 
176
 
 
177
                        if (NULL == (p = is_strprefix(q, http_prefix))) {
 
178
                                statusbar_gui_warning(10, _("MAGNET URI contained source URL "
 
179
                                        "for an unsupported protocol"));
 
180
                                /* Skip this parameter */
 
181
                                continue;
 
182
                        }
 
183
 
 
184
                        if (gchar_to_ip_strict(p, &addr, (const gchar **) &ep)) {
 
185
                                p = ep;
 
186
                        } else {
 
187
                                hostname = p;
 
188
                                p = strchr(p, ':');
 
189
                                if (!p)
 
190
                                        p = strchr(p, '/');
 
191
                                if (!p) {
 
192
                                        g_message("Missing path in HTTP URL");
 
193
                                        continue;
 
194
                                }
 
195
                        }
 
196
 
 
197
                        if (*p == ':') {
 
198
                                gchar *ep2;
 
199
                                gint error;
 
200
                                gulong v;
 
201
 
 
202
                                *p++ = '\0'; /* Terminate hostname */
 
203
                                v = gm_atoul(p, &ep2, &error);
 
204
                                if (error || v >= 65535) {
 
205
                                        g_message("TCP port is out of range");
 
206
                                        /* Skip this parameter */
 
207
                                        continue;
 
208
                                }
 
209
 
 
210
                                port = v;
 
211
                                p = ep2;
 
212
                        } else {
 
213
                                port = 80;
 
214
                        }
 
215
 
 
216
                        if (*p != '/') {
 
217
                                g_message("Expected port followed by '/'");
 
218
                                /* Skip this parameter */
 
219
                                continue;
 
220
                        }
 
221
                        g_assert(*p == '/');
 
222
 
 
223
                        if (!is_strprefix(p, n2r_query)) {
 
224
                                /* TODO:
 
225
                                 *                      Support e.g., "http://example.com/example.txt"
 
226
                                 */
 
227
                                g_message("Arbitrary HTTP URLs are not supported yet");
 
228
                                continue;
 
229
                        }
 
230
 
 
231
                        *p = '\0'; /* terminate hostname */
 
232
                        p += sizeof n2r_query - 1;
 
233
                        if (!is_strprefix(p, "urn:sha1:")) {
 
234
                                g_message("Expected ``urn:sha1:''");
 
235
                                continue;
 
236
                        }
 
237
 
 
238
                        hash = p;
 
239
                        if (!urn_get_sha1(hash, digest)) {
 
240
                                g_message("Bad SHA1 in MAGNET URI (%s)", hash);
 
241
                                continue;
 
242
                        }
 
243
 
 
244
                        dl.ip = addr;
 
245
                        dl.port = port;
 
246
                        dl.sha1 = digest;
 
247
                        dl.ready = TRUE;
 
248
                        dl.hostname = hostname;
 
249
                        if (!dl.file)
 
250
                                dl.file = hash;
 
251
                } else if (0 == strcmp(name, "xt")) {
 
252
                        /* eXact Topic search (by urn:sha1) */
 
253
                        if (!is_strprefix(q, "urn:sha1:")) {
 
254
                                statusbar_gui_warning(10, _("MAGNET URI contained exact topic "
 
255
                                        "search other than urn:sha1:"));
 
256
                                /* Skip this parameter */
 
257
                                continue;
 
258
                        }
 
259
                        search_gui_new_search(q, 0, NULL);
 
260
                } else if (0 == strcmp(name, "kt")) {
 
261
                        /* Keyword Topic search */
 
262
                        search_gui_new_search(q, 0, NULL);
 
263
                } else {
 
264
                        g_message("Unhandled parameter in MAGNET URI \"%s\"", name);
 
265
                }
 
266
 
 
267
        }
 
268
 
 
269
        /* FIXME:       As long as downloading of files without a known size is
 
270
         *                      defective, we cannot initiate downloads this way. */
 
271
#if 0
 
272
        if (dl.ready) {
 
273
                gchar *filename;
 
274
 
 
275
                filename = gm_sanitize_filename(dl.file, FALSE, FALSE);
 
276
 
 
277
                guc_download_new_unknown_size(filename, URN_INDEX, dl.ip,
 
278
                        dl.port, blank_guid, dl.hostname, dl.sha1, time(NULL),
 
279
                        FALSE, NULL, NULL);
 
280
                if (filename != dl.file)
 
281
                        G_FREE_NULL(filename);
 
282
        }
 
283
#endif
 
284
 
 
285
        return TRUE;
 
286
}
 
287
 
 
288
 
 
289
static void
 
290
drag_data_received(GtkWidget *unused_widget, GdkDragContext *dc,
 
291
        gint x, gint y, GtkSelectionData *data, guint info, guint stamp,
 
292
        gpointer unused_udata)
 
293
{
 
294
        gboolean succ = FALSE;
 
295
 
 
296
        (void) unused_widget;
 
297
        (void) unused_udata;
 
298
 
 
299
        if (gui_debug > 0)
 
300
                g_message("drag_data_received: x=%d, y=%d, info=%u, t=%u",
 
301
                        x, y, info, stamp);
 
302
        if (data->length > 0 && data->format == 8) {
 
303
                guint i;
 
304
                gchar *p, *url = (gchar *) data->data;
 
305
                size_t len;
 
306
 
 
307
                if (gui_debug > 0)
 
308
                        g_message("drag_data_received: url=\"%s\"", url);
 
309
 
 
310
 
 
311
                p = strchr(url, ':');
 
312
                len = p ? p - url : 0;
 
313
                if (!p || (ssize_t) len < 1) {
 
314
                        statusbar_gui_warning(10, _("Cannot handle the dropped data"));
 
315
                        goto cleanup;
 
316
                }
 
317
 
 
318
                for (i = 0; i < G_N_ELEMENTS(proto_handlers); i++)
 
319
                        if (is_strprefix(url, proto_handlers[i].proto)) {
 
320
                                succ = proto_handlers[i].handler(url);
 
321
                                break;
 
322
                        }
 
323
 
 
324
                if (i == G_N_ELEMENTS(proto_handlers))
 
325
                        statusbar_gui_warning(10, _("Protocol is not supported"));
 
326
        }
 
327
 
 
328
cleanup:
 
329
 
 
330
        gtk_drag_finish(dc, succ, FALSE, stamp);
 
331
}
 
332
 
 
333
/*
 
334
 * Public functions
 
335
 */
 
336
 
 
337
void drop_init(void)
 
338
{
 
339
        static const GtkTargetEntry targets[] = {
 
340
                { "STRING",             0, 23 },
 
341
                { "text/plain", 0, 23 },
 
342
        };
 
343
        GtkWidget *w = GTK_WIDGET(main_window);
 
344
 
 
345
        g_return_if_fail(!cb);
 
346
        cb = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
 
347
        g_return_if_fail(cb);
 
348
 
 
349
        g_signal_connect(G_OBJECT(w), "drag-data-received",
 
350
                G_CALLBACK(drag_data_received), NULL);
 
351
 
 
352
        gtk_drag_dest_set(w, GTK_DEST_DEFAULT_ALL, targets,
 
353
                G_N_ELEMENTS(targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
354
        gtk_drag_dest_set_target_list(w, gtk_target_list_new(targets,
 
355
                G_N_ELEMENTS(targets)));
 
356
}
 
357
 
 
358
void drop_close(void)
 
359
{
 
360
        /* Nothing ATM */
 
361
}
 
362
#endif /* USE_GTK2 */
 
363
 
 
364
#ifdef USE_GTK1
 
365
void drop_init(void)
 
366
{
 
367
        /* NOT IMPLEMENTED */
 
368
}
 
369
 
 
370
void drop_close(void)
 
371
{
 
372
        /* NOT IMPLEMENTED */
 
373
}
 
374
#endif
 
375
 
 
376
/* vi: set ts=4 sw=4 cindent: */