Changeset 5ebff60 for protocols/purple/ft.c
- Timestamp:
- 2015-02-20T22:50:54Z (9 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/purple/ft.c
raf359b4 r5ebff60 34 34 #include <purple.h> 35 35 36 struct prpl_xfer_data 37 { 36 struct prpl_xfer_data { 38 37 PurpleXfer *xfer; 39 38 file_transfer_t *ft; … … 46 45 static file_transfer_t *next_ft; 47 46 48 struct im_connection *purple_ic_by_pa( PurpleAccount *pa);49 static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond);50 static gboolean prpl_xfer_write_request( struct file_transfer *ft);47 struct im_connection *purple_ic_by_pa(PurpleAccount *pa); 48 static gboolean prplcb_xfer_new_send_cb(gpointer data, gint fd, b_input_condition cond); 49 static gboolean prpl_xfer_write_request(struct file_transfer *ft); 51 50 52 51 53 52 /* Receiving files (IM->UI): */ 54 static void prpl_xfer_accept( struct file_transfer *ft ) 55 { 56 struct prpl_xfer_data *px = ft->data; 57 purple_xfer_request_accepted( px->xfer, NULL ); 58 prpl_xfer_write_request( ft ); 59 } 60 61 static void prpl_xfer_canceled( struct file_transfer *ft, char *reason ) 62 { 63 struct prpl_xfer_data *px = ft->data; 64 purple_xfer_request_denied( px->xfer ); 65 } 66 67 static void prplcb_xfer_new( PurpleXfer *xfer ) 68 { 69 if( purple_xfer_get_type( xfer ) == PURPLE_XFER_RECEIVE ) 70 { 71 struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 ); 72 53 static void prpl_xfer_accept(struct file_transfer *ft) 54 { 55 struct prpl_xfer_data *px = ft->data; 56 57 purple_xfer_request_accepted(px->xfer, NULL); 58 prpl_xfer_write_request(ft); 59 } 60 61 static void prpl_xfer_canceled(struct file_transfer *ft, char *reason) 62 { 63 struct prpl_xfer_data *px = ft->data; 64 65 purple_xfer_request_denied(px->xfer); 66 } 67 68 static void prplcb_xfer_new(PurpleXfer *xfer) 69 { 70 if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) { 71 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 72 73 73 xfer->ui_data = px; 74 74 px->xfer = xfer; 75 px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ));75 px->fn = mktemp(g_strdup("/tmp/bitlbee-purple-ft.XXXXXX")); 76 76 px->fd = -1; 77 px->ic = purple_ic_by_pa( xfer->account);78 79 purple_xfer_set_local_filename( xfer, px->fn);80 77 px->ic = purple_ic_by_pa(xfer->account); 78 79 purple_xfer_set_local_filename(xfer, px->fn); 80 81 81 /* Sadly the xfer struct is still empty ATM so come back after 82 82 the caller is done. */ 83 b_timeout_add( 0, prplcb_xfer_new_send_cb, xfer ); 84 } 85 else 86 { 83 b_timeout_add(0, prplcb_xfer_new_send_cb, xfer); 84 } else { 87 85 struct file_transfer *ft = next_ft; 88 86 struct prpl_xfer_data *px = ft->data; 89 87 90 88 xfer->ui_data = px; 91 89 px->xfer = xfer; 92 90 93 91 next_ft = NULL; 94 92 } 95 93 } 96 94 97 static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond)95 static gboolean prplcb_xfer_new_send_cb(gpointer data, gint fd, b_input_condition cond) 98 96 { 99 97 PurpleXfer *xfer = data; 100 struct im_connection *ic = purple_ic_by_pa( xfer->account);98 struct im_connection *ic = purple_ic_by_pa(xfer->account); 101 99 struct prpl_xfer_data *px = xfer->ui_data; 102 100 PurpleBuddy *buddy; 103 101 const char *who; 104 105 buddy = purple_find_buddy( xfer->account, xfer->who);106 who = buddy ? purple_buddy_get_name( buddy) : xfer->who;107 102 103 buddy = purple_find_buddy(xfer->account, xfer->who); 104 who = buddy ? purple_buddy_get_name(buddy) : xfer->who; 105 108 106 /* TODO(wilmer): After spreading some more const goodness in BitlBee, 109 107 remove the evil cast below. */ 110 px->ft = imcb_file_send_start( ic, (char*) who, xfer->filename, xfer->size);108 px->ft = imcb_file_send_start(ic, (char *) who, xfer->filename, xfer->size); 111 109 px->ft->data = px; 112 110 113 111 px->ft->accept = prpl_xfer_accept; 114 112 px->ft->canceled = prpl_xfer_canceled; 115 113 px->ft->write_request = prpl_xfer_write_request; 116 114 117 115 return FALSE; 118 116 } 119 117 120 gboolean try_write_to_ui( gpointer data, gint fd, b_input_condition cond)118 gboolean try_write_to_ui(gpointer data, gint fd, b_input_condition cond) 121 119 { 122 120 struct file_transfer *ft = data; … … 124 122 struct stat fs; 125 123 off_t tx_bytes; 126 124 127 125 /* If we don't have the file opened yet, there's no data so wait. */ 128 if ( px->fd < 0 || !px->ui_wants_data )126 if (px->fd < 0 || !px->ui_wants_data) { 129 127 return FALSE; 130 131 tx_bytes = lseek( px->fd, 0, SEEK_CUR ); 132 fstat( px->fd, &fs);133 134 if( fs.st_size > tx_bytes ) 135 {128 } 129 130 tx_bytes = lseek(px->fd, 0, SEEK_CUR); 131 fstat(px->fd, &fs); 132 133 if (fs.st_size > tx_bytes) { 136 134 char buf[1024]; 137 size_t n = MIN( fs.st_size - tx_bytes, sizeof( buf ) ); 138 139 if( read( px->fd, buf, n ) == n && ft->write( ft, buf, n ) ) 140 { 135 size_t n = MIN(fs.st_size - tx_bytes, sizeof(buf)); 136 137 if (read(px->fd, buf, n) == n && ft->write(ft, buf, n)) { 141 138 px->ui_wants_data = FALSE; 139 } else { 140 purple_xfer_cancel_local(px->xfer); 141 imcb_file_canceled(px->ic, ft, "Read error"); 142 142 } 143 else 144 { 145 purple_xfer_cancel_local( px->xfer ); 146 imcb_file_canceled( px->ic, ft, "Read error" ); 147 } 148 } 149 150 if( lseek( px->fd, 0, SEEK_CUR ) == px->xfer->size ) 151 { 143 } 144 145 if (lseek(px->fd, 0, SEEK_CUR) == px->xfer->size) { 152 146 /*purple_xfer_end( px->xfer );*/ 153 imcb_file_finished( px->ic, ft);154 } 155 147 imcb_file_finished(px->ic, ft); 148 } 149 156 150 return FALSE; 157 151 } 158 152 159 153 /* UI calls this when its buffer is empty and wants more data to send to the user. */ 160 static gboolean prpl_xfer_write_request( struct file_transfer *ft)161 { 162 struct prpl_xfer_data *px = ft->data; 163 154 static gboolean prpl_xfer_write_request(struct file_transfer *ft) 155 { 156 struct prpl_xfer_data *px = ft->data; 157 164 158 px->ui_wants_data = TRUE; 165 try_write_to_ui( ft, 0, 0);166 159 try_write_to_ui(ft, 0, 0); 160 167 161 return FALSE; 168 162 } … … 170 164 171 165 /* Generic (IM<>UI): */ 172 static void prplcb_xfer_destroy( PurpleXfer *xfer)166 static void prplcb_xfer_destroy(PurpleXfer *xfer) 173 167 { 174 168 struct prpl_xfer_data *px = xfer->ui_data; 175 176 g_free( px->fn ); 177 g_free( px->handle ); 178 if( px->fd >= 0 ) 179 close( px->fd ); 180 g_free( px ); 181 } 182 183 static void prplcb_xfer_progress( PurpleXfer *xfer, double percent ) 169 170 g_free(px->fn); 171 g_free(px->handle); 172 if (px->fd >= 0) { 173 close(px->fd); 174 } 175 g_free(px); 176 } 177 178 static void prplcb_xfer_progress(PurpleXfer *xfer, double percent) 184 179 { 185 180 struct prpl_xfer_data *px = xfer->ui_data; 186 187 if ( px == NULL )181 182 if (px == NULL) { 188 183 return; 189 190 if( purple_xfer_get_type( xfer ) == PURPLE_XFER_SEND ) 191 { 192 if( *px->fn ) 193 { 184 } 185 186 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) { 187 if (*px->fn) { 194 188 char *slash; 195 196 unlink( px->fn ); 197 if( ( slash = strrchr( px->fn, '/' ) ) ) 198 { 189 190 unlink(px->fn); 191 if ((slash = strrchr(px->fn, '/'))) { 199 192 *slash = '\0'; 200 rmdir( px->fn);193 rmdir(px->fn); 201 194 } 202 195 *px->fn = '\0'; 203 196 } 204 197 205 198 return; 206 199 } 207 208 if( px->fd == -1 && percent > 0 ) 209 { 200 201 if (px->fd == -1 && percent > 0) { 210 202 /* Weeeeeeeee, we're getting data! That means the file exists 211 203 by now so open it and start sending to the UI. */ 212 px->fd = open( px->fn, O_RDONLY);213 204 px->fd = open(px->fn, O_RDONLY); 205 214 206 /* Unlink it now, because we don't need it after this. */ 215 unlink( px->fn);216 } 217 218 if ( percent < 1 )219 try_write_to_ui( px->ft, 0, 0);220 else207 unlink(px->fn); 208 } 209 210 if (percent < 1) { 211 try_write_to_ui(px->ft, 0, 0); 212 } else { 221 213 /* Another nice problem: If we have the whole file, it only 222 214 gets closed when we return. Problem: There may still be 223 215 stuff buffered and not written, we'll only see it after 224 216 the caller close()s the file. So poll the file after that. */ 225 b_timeout_add( 0, try_write_to_ui, px->ft ); 226 } 227 228 static void prplcb_xfer_cancel_remote( PurpleXfer *xfer ) 217 b_timeout_add(0, try_write_to_ui, px->ft); 218 } 219 } 220 221 static void prplcb_xfer_cancel_remote(PurpleXfer *xfer) 229 222 { 230 223 struct prpl_xfer_data *px = xfer->ui_data; 231 232 if ( px->ft )233 imcb_file_canceled( px->ic, px->ft, "Canceled by remote end");234 else224 225 if (px->ft) { 226 imcb_file_canceled(px->ic, px->ft, "Canceled by remote end"); 227 } else { 235 228 /* px->ft == NULL for sends, because of the two stages. :-/ */ 236 imcb_error( px->ic, "File transfer cancelled by remote end" ); 237 } 238 239 static void prplcb_xfer_dbg( PurpleXfer *xfer ) 240 { 241 fprintf( stderr, "prplcb_xfer_dbg 0x%p\n", xfer ); 229 imcb_error(px->ic, "File transfer cancelled by remote end"); 230 } 231 } 232 233 static void prplcb_xfer_dbg(PurpleXfer *xfer) 234 { 235 fprintf(stderr, "prplcb_xfer_dbg 0x%p\n", xfer); 242 236 } 243 237 244 238 245 239 /* Sending files (UI->IM): */ 246 static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigned int len);247 static gboolean purple_transfer_request_cb( gpointer data, gint fd, b_input_condition cond);248 249 void purple_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *handle)250 { 251 struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1);240 static gboolean prpl_xfer_write(struct file_transfer *ft, char *buffer, unsigned int len); 241 static gboolean purple_transfer_request_cb(gpointer data, gint fd, b_input_condition cond); 242 243 void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle) 244 { 245 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 252 246 char *dir, *basename; 253 247 254 248 ft->data = px; 255 249 px->ft = ft; 256 257 dir = g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ); 258 if( !mkdtemp( dir ) ) 259 { 260 imcb_error( ic, "Could not create temporary file for file transfer" ); 261 g_free( px ); 262 g_free( dir ); 250 251 dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"); 252 if (!mkdtemp(dir)) { 253 imcb_error(ic, "Could not create temporary file for file transfer"); 254 g_free(px); 255 g_free(dir); 263 256 return; 264 257 } 265 266 if ( ( basename = strrchr( ft->file_name, '/' ) ) )258 259 if ((basename = strrchr(ft->file_name, '/'))) { 267 260 basename++; 268 else261 } else { 269 262 basename = ft->file_name; 270 px->fn = g_strdup_printf( "%s/%s", dir, basename );271 px->f d = open( px->fn, O_WRONLY | O_CREAT, 0600);272 g_free( dir);273 274 if( px->fd < 0 ) 275 {276 imcb_error( ic, "Could not create temporary file for file transfer");277 g_free( px);278 g_free( px->fn);263 } 264 px->fn = g_strdup_printf("%s/%s", dir, basename); 265 px->fd = open(px->fn, O_WRONLY | O_CREAT, 0600); 266 g_free(dir); 267 268 if (px->fd < 0) { 269 imcb_error(ic, "Could not create temporary file for file transfer"); 270 g_free(px); 271 g_free(px->fn); 279 272 return; 280 273 } 281 274 282 275 px->ic = ic; 283 px->handle = g_strdup( handle ); 284 285 imcb_log( ic, "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..." ); 286 287 b_timeout_add( 0, purple_transfer_request_cb, ft ); 288 } 289 290 static void purple_transfer_forward( struct file_transfer *ft ) 276 px->handle = g_strdup(handle); 277 278 imcb_log(ic, 279 "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..."); 280 281 b_timeout_add(0, purple_transfer_request_cb, ft); 282 } 283 284 static void purple_transfer_forward(struct file_transfer *ft) 291 285 { 292 286 struct prpl_xfer_data *px = ft->data; 293 287 PurpleAccount *pa = px->ic->proto_data; 294 288 295 289 /* xfer_new() will pick up this variable. It's a hack but we're not 296 290 multi-threaded anyway. */ 297 291 next_ft = ft; 298 serv_send_file( purple_account_get_connection( pa ), px->handle, px->fn);299 } 300 301 static gboolean purple_transfer_request_cb( gpointer data, gint fd, b_input_condition cond)292 serv_send_file(purple_account_get_connection(pa), px->handle, px->fn); 293 } 294 295 static gboolean purple_transfer_request_cb(gpointer data, gint fd, b_input_condition cond) 302 296 { 303 297 file_transfer_t *ft = data; 304 298 struct prpl_xfer_data *px = ft->data; 305 306 if( ft->write == NULL ) 307 { 299 300 if (ft->write == NULL) { 308 301 ft->write = prpl_xfer_write; 309 imcb_file_recv_start( px->ic, ft);310 } 311 312 ft->write_request( ft);313 302 imcb_file_recv_start(px->ic, ft); 303 } 304 305 ft->write_request(ft); 306 314 307 return FALSE; 315 308 } 316 309 317 static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigned int len ) 318 { 319 struct prpl_xfer_data *px = ft->data; 320 321 if( write( px->fd, buffer, len ) != len ) 322 { 323 imcb_file_canceled( px->ic, ft, "Error while writing temporary file" ); 310 static gboolean prpl_xfer_write(struct file_transfer *ft, char *buffer, unsigned int len) 311 { 312 struct prpl_xfer_data *px = ft->data; 313 314 if (write(px->fd, buffer, len) != len) { 315 imcb_file_canceled(px->ic, ft, "Error while writing temporary file"); 324 316 return FALSE; 325 317 } 326 327 if( lseek( px->fd, 0, SEEK_CUR ) >= ft->file_size ) 328 { 329 close( px->fd ); 318 319 if (lseek(px->fd, 0, SEEK_CUR) >= ft->file_size) { 320 close(px->fd); 330 321 px->fd = -1; 331 332 purple_transfer_forward( ft);333 imcb_file_finished( px->ic, ft);322 323 purple_transfer_forward(ft); 324 imcb_file_finished(px->ic, ft); 334 325 px->ft = NULL; 335 } 336 else337 b_timeout_add( 0, purple_transfer_request_cb, ft );338 326 } else { 327 b_timeout_add(0, purple_transfer_request_cb, ft); 328 } 329 339 330 return TRUE; 340 331 }
Note: See TracChangeset
for help on using the changeset viewer.