Mercurial > pidgin
comparison libpurple/protocols/irc/dcc_send.c @ 32819:2c6510167895 default tip
propagate from branch 'im.pidgin.pidgin.2.x.y' (head 3315c5dfbd0ad16511bdcf865e5b07c02d07df24)
to branch 'im.pidgin.pidgin' (head cbd1eda6bcbf0565ae7766396bb8f6f419cb6a9a)
| author | Elliott Sales de Andrade <qulogic@pidgin.im> |
|---|---|
| date | Sat, 02 Jun 2012 02:30:49 +0000 |
| parents | 1f56d5102483 |
| children |
comparison
equal
deleted
inserted
replaced
| 32818:01ff09d4a463 | 32819:2c6510167895 |
|---|---|
| 32 * Functions related to receiving files via DCC SEND | 32 * Functions related to receiving files via DCC SEND |
| 33 ***************************************************************************/ | 33 ***************************************************************************/ |
| 34 | 34 |
| 35 struct irc_xfer_rx_data { | 35 struct irc_xfer_rx_data { |
| 36 gchar *ip; | 36 gchar *ip; |
| 37 unsigned int remote_port; | |
| 37 }; | 38 }; |
| 38 | 39 |
| 39 static void irc_dccsend_recv_destroy(PurpleXfer *xfer) | 40 static void irc_dccsend_recv_destroy(PurpleXfer *xfer) |
| 40 { | 41 { |
| 41 struct irc_xfer_rx_data *xd = xfer->data; | 42 struct irc_xfer_rx_data *xd = purple_xfer_get_protocol_data(xfer); |
| 42 | 43 |
| 43 g_free(xd->ip); | 44 g_free(xd->ip); |
| 44 g_free(xd); | 45 g_free(xd); |
| 45 } | 46 } |
| 46 | 47 |
| 49 * It sends the acknowledgement (in the form of a total byte count as an | 50 * It sends the acknowledgement (in the form of a total byte count as an |
| 50 * unsigned 4 byte integer in network byte order) | 51 * unsigned 4 byte integer in network byte order) |
| 51 */ | 52 */ |
| 52 static void irc_dccsend_recv_ack(PurpleXfer *xfer, const guchar *data, size_t size) { | 53 static void irc_dccsend_recv_ack(PurpleXfer *xfer, const guchar *data, size_t size) { |
| 53 guint32 l; | 54 guint32 l; |
| 54 size_t result; | 55 gssize result; |
| 55 | 56 |
| 56 l = htonl(xfer->bytes_sent); | 57 l = htonl(purple_xfer_get_bytes_sent(xfer)); |
| 57 result = write(xfer->fd, &l, sizeof(l)); | 58 result = purple_xfer_write(xfer, (guchar *)&l, sizeof(l)); |
| 58 if (result != sizeof(l)) { | 59 if (result != sizeof(l)) { |
| 59 purple_debug_error("irc", "unable to send acknowledgement: %s\n", g_strerror(errno)); | 60 purple_debug_error("irc", "unable to send acknowledgement: %s\n", g_strerror(errno)); |
| 60 /* TODO: We should probably close the connection here or something. */ | 61 /* TODO: We should probably close the connection here or something. */ |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 | 64 |
| 64 static void irc_dccsend_recv_init(PurpleXfer *xfer) { | 65 static void irc_dccsend_recv_init(PurpleXfer *xfer) { |
| 65 struct irc_xfer_rx_data *xd = xfer->data; | 66 struct irc_xfer_rx_data *xd = purple_xfer_get_protocol_data(xfer); |
| 66 | 67 |
| 67 purple_xfer_start(xfer, -1, xd->ip, xfer->remote_port); | 68 purple_xfer_start(xfer, -1, xd->ip, xd->remote_port); |
| 68 g_free(xd->ip); | 69 g_free(xd->ip); |
| 69 xd->ip = NULL; | 70 xd->ip = NULL; |
| 70 } | 71 } |
| 71 | 72 |
| 72 /* This function makes the necessary arrangements for receiving files */ | 73 /* This function makes the necessary arrangements for receiving files */ |
| 112 | 113 |
| 113 xfer = purple_xfer_new(irc->account, PURPLE_XFER_RECEIVE, from); | 114 xfer = purple_xfer_new(irc->account, PURPLE_XFER_RECEIVE, from); |
| 114 if (xfer) | 115 if (xfer) |
| 115 { | 116 { |
| 116 xd = g_new0(struct irc_xfer_rx_data, 1); | 117 xd = g_new0(struct irc_xfer_rx_data, 1); |
| 117 xfer->data = xd; | 118 purple_xfer_set_protocol_data(xfer, xd); |
| 118 | 119 |
| 119 purple_xfer_set_filename(xfer, filename->str); | 120 purple_xfer_set_filename(xfer, filename->str); |
| 120 xfer->remote_port = atoi(token[i+1]); | 121 xd->remote_port = atoi(token[i+1]); |
| 121 | 122 |
| 122 nip = strtoul(token[i], NULL, 10); | 123 nip = strtoul(token[i], NULL, 10); |
| 123 if (nip) { | 124 if (nip) { |
| 124 addr.s_addr = htonl(nip); | 125 addr.s_addr = htonl(nip); |
| 125 xd->ip = g_strdup(inet_ntoa(addr)); | 126 xd->ip = g_strdup(inet_ntoa(addr)); |
| 155 guint rxlen; | 156 guint rxlen; |
| 156 }; | 157 }; |
| 157 | 158 |
| 158 static void irc_dccsend_send_destroy(PurpleXfer *xfer) | 159 static void irc_dccsend_send_destroy(PurpleXfer *xfer) |
| 159 { | 160 { |
| 160 struct irc_xfer_send_data *xd = xfer->data; | 161 struct irc_xfer_send_data *xd = purple_xfer_get_protocol_data(xfer); |
| 161 | 162 |
| 162 if (xd == NULL) | 163 if (xd == NULL) |
| 163 return; | 164 return; |
| 164 | 165 |
| 165 if (xd->listen_data != NULL) | 166 if (xd->listen_data != NULL) |
| 176 | 177 |
| 177 /* just in case you were wondering, this is why DCC is gay */ | 178 /* just in case you were wondering, this is why DCC is gay */ |
| 178 static void irc_dccsend_send_read(gpointer data, int source, PurpleInputCondition cond) | 179 static void irc_dccsend_send_read(gpointer data, int source, PurpleInputCondition cond) |
| 179 { | 180 { |
| 180 PurpleXfer *xfer = data; | 181 PurpleXfer *xfer = data; |
| 181 struct irc_xfer_send_data *xd = xfer->data; | 182 struct irc_xfer_send_data *xd = purple_xfer_get_protocol_data(xfer); |
| 182 char buffer[64]; | 183 char buffer[64]; |
| 183 int len; | 184 int len; |
| 184 | 185 |
| 185 len = read(source, buffer, sizeof(buffer)); | 186 len = read(source, buffer, sizeof(buffer)); |
| 186 | 187 |
| 226 } | 227 } |
| 227 | 228 |
| 228 static gssize irc_dccsend_send_write(const guchar *buffer, size_t size, PurpleXfer *xfer) | 229 static gssize irc_dccsend_send_write(const guchar *buffer, size_t size, PurpleXfer *xfer) |
| 229 { | 230 { |
| 230 gssize s; | 231 gssize s; |
| 231 int ret; | 232 gssize ret; |
| 232 | 233 |
| 233 s = MIN(purple_xfer_get_bytes_remaining(xfer), size); | 234 s = MIN(purple_xfer_get_bytes_remaining(xfer), size); |
| 234 if (!s) | 235 if (!s) |
| 235 return 0; | 236 return 0; |
| 236 | 237 |
| 237 ret = write(xfer->fd, buffer, s); | 238 ret = purple_xfer_write(xfer, buffer, s); |
| 238 | 239 |
| 239 if (ret < 0 && errno == EAGAIN) | 240 if (ret < 0 && errno == EAGAIN) |
| 240 ret = 0; | 241 ret = 0; |
| 241 | 242 |
| 242 return ret; | 243 return ret; |
| 243 } | 244 } |
| 244 | 245 |
| 245 static void irc_dccsend_send_connected(gpointer data, int source, PurpleInputCondition cond) { | 246 static void irc_dccsend_send_connected(gpointer data, int source, PurpleInputCondition cond) { |
| 246 PurpleXfer *xfer = (PurpleXfer *) data; | 247 PurpleXfer *xfer = (PurpleXfer *) data; |
| 247 struct irc_xfer_send_data *xd = xfer->data; | 248 struct irc_xfer_send_data *xd = purple_xfer_get_protocol_data(xfer); |
| 248 int conn, flags; | 249 int conn, flags; |
| 249 | 250 |
| 250 conn = accept(xd->fd, NULL, 0); | 251 conn = accept(xd->fd, NULL, 0); |
| 251 if (conn == -1) { | 252 if (conn == -1) { |
| 252 /* Accepting the connection failed. This could just be related | 253 /* Accepting the connection failed. This could just be related |
| 255 /* Let's print an error message anyway */ | 256 /* Let's print an error message anyway */ |
| 256 purple_debug_warning("irc", "accept: %s\n", g_strerror(errno)); | 257 purple_debug_warning("irc", "accept: %s\n", g_strerror(errno)); |
| 257 return; | 258 return; |
| 258 } | 259 } |
| 259 | 260 |
| 260 purple_input_remove(xfer->watcher); | 261 purple_input_remove(purple_xfer_get_watcher(xfer)); |
| 261 xfer->watcher = 0; | 262 purple_xfer_set_watcher(xfer, 0); |
| 262 close(xd->fd); | 263 close(xd->fd); |
| 263 xd->fd = -1; | 264 xd->fd = -1; |
| 264 | 265 |
| 265 flags = fcntl(conn, F_GETFL); | 266 flags = fcntl(conn, F_GETFL); |
| 266 fcntl(conn, F_SETFL, flags | O_NONBLOCK); | 267 fcntl(conn, F_SETFL, flags | O_NONBLOCK); |
| 283 const char *arg[2]; | 284 const char *arg[2]; |
| 284 char *tmp; | 285 char *tmp; |
| 285 struct in_addr addr; | 286 struct in_addr addr; |
| 286 unsigned short int port; | 287 unsigned short int port; |
| 287 | 288 |
| 288 xd = xfer->data; | 289 xd = purple_xfer_get_protocol_data(xfer); |
| 289 xd->listen_data = NULL; | 290 xd->listen_data = NULL; |
| 290 | 291 |
| 291 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL | 292 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL |
| 292 || purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_REMOTE) { | 293 || purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_REMOTE) { |
| 293 purple_xfer_unref(xfer); | 294 purple_xfer_unref(xfer); |
| 294 return; | 295 return; |
| 295 } | 296 } |
| 296 | 297 |
| 297 xd = xfer->data; | 298 xd = purple_xfer_get_protocol_data(xfer); |
| 298 gc = purple_account_get_connection(purple_xfer_get_account(xfer)); | 299 gc = purple_account_get_connection(purple_xfer_get_account(xfer)); |
| 299 irc = gc->proto_data; | 300 irc = purple_connection_get_protocol_data(gc); |
| 300 | 301 |
| 301 purple_xfer_unref(xfer); | 302 purple_xfer_unref(xfer); |
| 302 | 303 |
| 303 if (sock < 0) { | 304 if (sock < 0) { |
| 304 purple_notify_error(gc, NULL, _("File Transfer Failed"), | 305 purple_notify_error(gc, NULL, _("File Transfer Failed"), |
| 310 xd->fd = sock; | 311 xd->fd = sock; |
| 311 | 312 |
| 312 port = purple_network_get_port_from_fd(sock); | 313 port = purple_network_get_port_from_fd(sock); |
| 313 purple_debug_misc("irc", "port is %hu\n", port); | 314 purple_debug_misc("irc", "port is %hu\n", port); |
| 314 /* Monitor the listening socket */ | 315 /* Monitor the listening socket */ |
| 315 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, | 316 purple_xfer_set_watcher(xfer, purple_input_add(sock, PURPLE_INPUT_READ, |
| 316 irc_dccsend_send_connected, xfer); | 317 irc_dccsend_send_connected, xfer)); |
| 317 | 318 |
| 318 /* Send the intended recipient the DCC request */ | 319 /* Send the intended recipient the DCC request */ |
| 319 arg[0] = xfer->who; | 320 arg[0] = purple_xfer_get_remote_user(xfer); |
| 320 inet_aton(purple_network_get_my_ip(irc->fd), &addr); | 321 inet_aton(purple_network_get_my_ip(irc->fd), &addr); |
| 321 arg[1] = tmp = g_strdup_printf("\001DCC SEND \"%s\" %u %hu %" G_GSIZE_FORMAT "\001", | 322 arg[1] = tmp = g_strdup_printf("\001DCC SEND \"%s\" %u %hu %" G_GOFFSET_FORMAT "\001", |
| 322 xfer->filename, ntohl(addr.s_addr), | 323 purple_xfer_get_filename(xfer), ntohl(addr.s_addr), |
| 323 port, xfer->size); | 324 port, purple_xfer_get_size(xfer)); |
| 324 | 325 |
| 325 irc_cmd_privmsg(gc->proto_data, "msg", NULL, arg); | 326 irc_cmd_privmsg(purple_connection_get_protocol_data(gc), "msg", NULL, arg); |
| 326 g_free(tmp); | 327 g_free(tmp); |
| 327 } | 328 } |
| 328 | 329 |
| 329 /* | 330 /* |
| 330 * This function is called after the user has selected a file to send. | 331 * This function is called after the user has selected a file to send. |
| 331 */ | 332 */ |
| 332 static void irc_dccsend_send_init(PurpleXfer *xfer) { | 333 static void irc_dccsend_send_init(PurpleXfer *xfer) { |
| 333 PurpleConnection *gc = purple_account_get_connection(purple_xfer_get_account(xfer)); | 334 PurpleConnection *gc = purple_account_get_connection(purple_xfer_get_account(xfer)); |
| 334 struct irc_xfer_send_data *xd = xfer->data; | 335 struct irc_xfer_send_data *xd = purple_xfer_get_protocol_data(xfer); |
| 335 | 336 |
| 336 xfer->filename = g_path_get_basename(xfer->local_filename); | 337 purple_xfer_set_filename(xfer, g_path_get_basename(purple_xfer_get_local_filename(xfer))); |
| 337 | 338 |
| 338 purple_xfer_ref(xfer); | 339 purple_xfer_ref(xfer); |
| 339 | 340 |
| 340 /* Create a listening socket */ | 341 /* Create a listening socket */ |
| 341 xd->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM, | 342 xd->listen_data = purple_network_listen_range(0, 0, AF_UNSPEC, SOCK_STREAM, TRUE, |
| 342 irc_dccsend_network_listen_cb, xfer); | 343 irc_dccsend_network_listen_cb, xfer); |
| 343 if (xd->listen_data == NULL) { | 344 if (xd->listen_data == NULL) { |
| 344 purple_xfer_unref(xfer); | 345 purple_xfer_unref(xfer); |
| 345 purple_notify_error(gc, NULL, _("File Transfer Failed"), | 346 purple_notify_error(gc, NULL, _("File Transfer Failed"), |
| 346 _("Unable to open a listening port.")); | 347 _("Unable to open a listening port.")); |
| 357 xfer = purple_xfer_new(purple_connection_get_account(gc), PURPLE_XFER_SEND, who); | 358 xfer = purple_xfer_new(purple_connection_get_account(gc), PURPLE_XFER_SEND, who); |
| 358 if (xfer) | 359 if (xfer) |
| 359 { | 360 { |
| 360 xd = g_new0(struct irc_xfer_send_data, 1); | 361 xd = g_new0(struct irc_xfer_send_data, 1); |
| 361 xd->fd = -1; | 362 xd->fd = -1; |
| 362 xfer->data = xd; | 363 purple_xfer_set_protocol_data(xfer, xd); |
| 363 | 364 |
| 364 /* Setup our I/O op functions */ | 365 /* Setup our I/O op functions */ |
| 365 purple_xfer_set_init_fnc(xfer, irc_dccsend_send_init); | 366 purple_xfer_set_init_fnc(xfer, irc_dccsend_send_init); |
| 366 purple_xfer_set_write_fnc(xfer, irc_dccsend_send_write); | 367 purple_xfer_set_write_fnc(xfer, irc_dccsend_send_write); |
| 367 purple_xfer_set_end_fnc(xfer, irc_dccsend_send_destroy); | 368 purple_xfer_set_end_fnc(xfer, irc_dccsend_send_destroy); |
