source: protocols/purple/ft-direct.c @ 3fb7139

Last change on this file since 3fb7139 was d93c8beb, checked in by dequis <dx@…>, at 2015-03-02T03:27:16Z

purple: move PurpleAccount from proto_data in a struct purple_data

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  libpurple module - File transfer stuff                                   *
5*                                                                           *
6*  Copyright 2009-2010 Wilmer van der Gaast <wilmer@gaast.net>              *
7*                                                                           *
8*  This program 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*  This program 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 along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24/* This code tries to do direct file transfers, i.e. without caching the file
25   locally on disk first. Since libpurple can only do this since version 2.6.0
26   and even then very unreliably (and not with all IM modules), I'm canning
27   this code for now. */
28
29#include "bitlbee.h"
30#include "bpurple.h"
31
32#include <stdarg.h>
33
34#include <glib.h>
35#include <purple.h>
36
37struct prpl_xfer_data {
38        PurpleXfer *xfer;
39        file_transfer_t *ft;
40        gint ready_timer;
41        char *buf;
42        int buf_len;
43};
44
45static file_transfer_t *next_ft;
46
47struct im_connection *purple_ic_by_pa(PurpleAccount *pa);
48
49/* Glorious hack: We seem to have to remind at least some libpurple plugins
50   that we're ready because this info may get lost if we give it too early.
51   So just do it ten times a second. :-/ */
52static gboolean prplcb_xfer_write_request_cb(gpointer data, gint fd, b_input_condition cond)
53{
54        struct prpl_xfer_data *px = data;
55
56        purple_xfer_ui_ready(px->xfer);
57
58        return purple_xfer_get_type(px->xfer) == PURPLE_XFER_RECEIVE;
59}
60
61static gboolean prpl_xfer_write_request(struct file_transfer *ft)
62{
63        struct prpl_xfer_data *px = ft->data;
64
65        px->ready_timer = b_timeout_add(100, prplcb_xfer_write_request_cb, px);
66        return TRUE;
67}
68
69static gboolean prpl_xfer_write(struct file_transfer *ft, char *buffer, unsigned int len)
70{
71        struct prpl_xfer_data *px = ft->data;
72
73        px->buf = g_memdup(buffer, len);
74        px->buf_len = len;
75
76        //purple_xfer_ui_ready( px->xfer );
77        px->ready_timer = b_timeout_add(0, prplcb_xfer_write_request_cb, px);
78
79        return TRUE;
80}
81
82static void prpl_xfer_accept(struct file_transfer *ft)
83{
84        struct prpl_xfer_data *px = ft->data;
85
86        purple_xfer_request_accepted(px->xfer, NULL);
87        prpl_xfer_write_request(ft);
88}
89
90static void prpl_xfer_canceled(struct file_transfer *ft, char *reason)
91{
92        struct prpl_xfer_data *px = ft->data;
93
94        purple_xfer_request_denied(px->xfer);
95}
96
97static gboolean prplcb_xfer_new_send_cb(gpointer data, gint fd, b_input_condition cond)
98{
99        PurpleXfer *xfer = data;
100        struct im_connection *ic = purple_ic_by_pa(xfer->account);
101        struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1);
102        PurpleBuddy *buddy;
103        const char *who;
104
105        buddy = purple_find_buddy(xfer->account, xfer->who);
106        who = buddy ? purple_buddy_get_name(buddy) : xfer->who;
107
108        /* TODO(wilmer): After spreading some more const goodness in BitlBee,
109           remove the evil cast below. */
110        px->ft = imcb_file_send_start(ic, (char *) who, xfer->filename, xfer->size);
111        px->ft->data = px;
112        px->xfer = data;
113        px->xfer->ui_data = px;
114
115        px->ft->accept = prpl_xfer_accept;
116        px->ft->canceled = prpl_xfer_canceled;
117        px->ft->write_request = prpl_xfer_write_request;
118
119        return FALSE;
120}
121
122static void prplcb_xfer_new(PurpleXfer *xfer)
123{
124        if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) {
125                /* This should suppress the stupid file dialog. */
126                purple_xfer_set_local_filename(xfer, "/tmp/wtf123");
127
128                /* Sadly the xfer struct is still empty ATM so come back after
129                   the caller is done. */
130                b_timeout_add(0, prplcb_xfer_new_send_cb, xfer);
131        } else {
132                struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1);
133
134                px->ft = next_ft;
135                px->ft->data = px;
136                px->xfer = xfer;
137                px->xfer->ui_data = px;
138
139                purple_xfer_set_filename(xfer, px->ft->file_name);
140                purple_xfer_set_size(xfer, px->ft->file_size);
141
142                next_ft = NULL;
143        }
144}
145
146static void prplcb_xfer_progress(PurpleXfer *xfer, double percent)
147{
148        fprintf(stderr, "prplcb_xfer_dbg 0x%p %f\n", xfer, percent);
149}
150
151static void prplcb_xfer_dbg(PurpleXfer *xfer)
152{
153        fprintf(stderr, "prplcb_xfer_dbg 0x%p\n", xfer);
154}
155
156static gssize prplcb_xfer_write(PurpleXfer *xfer, const guchar *buffer, gssize size)
157{
158        struct prpl_xfer_data *px = xfer->ui_data;
159        gboolean st;
160
161        fprintf(stderr, "xfer_write %d %d\n", size, px->buf_len);
162
163        b_event_remove(px->ready_timer);
164        px->ready_timer = 0;
165
166        st = px->ft->write(px->ft, (char *) buffer, size);
167
168        if (st && xfer->bytes_remaining == size) {
169                imcb_file_finished(px->ft);
170        }
171
172        return st ? size : 0;
173}
174
175gssize prplcb_xfer_read(PurpleXfer *xfer, guchar **buffer, gssize size)
176{
177        struct prpl_xfer_data *px = xfer->ui_data;
178
179        fprintf(stderr, "xfer_read %d %d\n", size, px->buf_len);
180
181        if (px->buf) {
182                *buffer = px->buf;
183                px->buf = NULL;
184
185                px->ft->write_request(px->ft);
186
187                return px->buf_len;
188        }
189
190        return 0;
191}
192
193PurpleXferUiOps bee_xfer_uiops =
194{
195        prplcb_xfer_new,
196        prplcb_xfer_dbg,
197        prplcb_xfer_dbg,
198        prplcb_xfer_progress,
199        prplcb_xfer_dbg,
200        prplcb_xfer_dbg,
201        prplcb_xfer_write,
202        prplcb_xfer_read,
203        prplcb_xfer_dbg,
204};
205
206static gboolean prplcb_xfer_send_cb(gpointer data, gint fd, b_input_condition cond);
207
208void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle)
209{
210        struct purple_data *pd = ic->proto_data;
211        struct prpl_xfer_data *px;
212
213        /* xfer_new() will pick up this variable. It's a hack but we're not
214           multi-threaded anyway. */
215        next_ft = ft;
216        serv_send_file(purple_account_get_connection(pd->account), handle,
217                       ft->file_name);
218
219        ft->write = prpl_xfer_write;
220
221        px = ft->data;
222        imcb_file_recv_start(ft);
223
224        px->ready_timer = b_timeout_add(100, prplcb_xfer_send_cb, px);
225}
226
227static gboolean prplcb_xfer_send_cb(gpointer data, gint fd, b_input_condition cond)
228{
229        struct prpl_xfer_data *px = data;
230
231        if (px->ft->status & FT_STATUS_TRANSFERRING) {
232                fprintf(stderr, "The ft, it is ready...\n");
233                px->ft->write_request(px->ft);
234
235                return FALSE;
236        }
237
238        return TRUE;
239}
Note: See TracBrowser for help on using the repository browser.