jingle-filetransfer/filetransfer.c
changeset 126 059a6737f6a4
parent 125 3b640eb09fbd
child 128 cded9f40039e
equal deleted inserted replaced
125:3b640eb09fbd 126:059a6737f6a4
   205   // TODO: check if the file already exist or if it was created
   205   // TODO: check if the file already exist or if it was created
   206   // during the call to jingle_ft_check and handle_data
   206   // during the call to jingle_ft_check and handle_data
   207   if (jft->outfile == NULL) {
   207   if (jft->outfile == NULL) {
   208     jft->outfile = g_io_channel_new_file(jft->name, "w", &err);
   208     jft->outfile = g_io_channel_new_file(jft->name, "w", &err);
   209     if (jft->outfile == NULL || err != NULL) {
   209     if (jft->outfile == NULL || err != NULL) {
   210       // propagate the GError ?
   210       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   211                    jft->name);
       
   212     //TODO: propagate the GError ?
       
   213       g_error_free(err);
   211       return FALSE;
   214       return FALSE;
   212 	}
   215 	}
   213 	g_io_channel_set_encoding(jft->outfile, NULL, NULL);
   216 	status = g_io_channel_set_encoding(jft->outfile, NULL, &err);
       
   217 	if (status != G_IO_STATUS_NORMAL || err != NULL) {
       
   218      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   219                   jft->name);
       
   220      g_error_free(err);
       
   221      return FALSE;
       
   222    }
   214   }
   223   }
   215 
   224 
   216   status = g_io_channel_write_chars(jft->outfile, data, (gssize) len,
   225   status = g_io_channel_write_chars(jft->outfile, data, (gssize) len,
   217                                     &bytes_written, &err);
   226                                     &bytes_written, &err);
   218   g_io_channel_flush(jft->outfile, NULL);
       
   219   if (status != G_IO_STATUS_NORMAL || err != NULL) {
   227   if (status != G_IO_STATUS_NORMAL || err != NULL) {
       
   228      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   229                   jft->name);
       
   230     g_error_free(err);
   220     return FALSE;
   231     return FALSE;
   221   }
   232   }
       
   233   status = g_io_channel_flush(jft->outfile, &err);
       
   234   if (status != G_IO_STATUS_NORMAL || err != NULL) {
       
   235     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   236                  jft->name);
       
   237     g_error_free(err);
       
   238     return FALSE;
       
   239   }
       
   240 
   222   if (bytes_written != len) {
   241   if (bytes_written != len) {
   223     // not supposed to happen if status is normal, unless outfile is non-blocking
   242     // not supposed to happen if status is normal, unless outfile is non-blocking
   224     return FALSE;
   243     return FALSE;
   225   }
   244   }
   226   return TRUE;
   245   return TRUE;
   257     gchar *sid = jingle_generate_sid();
   276     gchar *sid = jingle_generate_sid();
   258     gchar *ressource, *recipientjid;
   277     gchar *ressource, *recipientjid;
   259     const gchar *namespaces[] = {NS_JINGLE, NS_JINGLE_APP_FT, NULL};
   278     const gchar *namespaces[] = {NS_JINGLE, NS_JINGLE_APP_FT, NULL};
   260     const gchar *myjid = g_strdup(lm_connection_get_jid(lconnection));
   279     const gchar *myjid = g_strdup(lm_connection_get_jid(lconnection));
   261     JingleFT *jft = g_new0(JingleFT, 1);
   280     JingleFT *jft = g_new0(JingleFT, 1);
   262 
   281     GError *err = NULL;
       
   282     
   263     if (CURRENT_JID == NULL) { // CURRENT_JID = the jid of the user which has focus
   283     if (CURRENT_JID == NULL) { // CURRENT_JID = the jid of the user which has focus
   264       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Please, choose a valid JID in the roster");
   284       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Please, choose a valid JID in the roster");
   265       return;
   285       return;
   266     }
   286     }
   267     ressource = jingle_find_compatible_res(CURRENT_JID, namespaces);
   287     ressource = jingle_find_compatible_res(CURRENT_JID, namespaces);
   278     jft->desc = g_strdup(args[0]);
   298     jft->desc = g_strdup(args[0]);
   279     jft->type = JINGLE_FT_OFFER;
   299     jft->type = JINGLE_FT_OFFER;
   280     jft->name = g_path_get_basename(filename);
   300     jft->name = g_path_get_basename(filename);
   281     jft->date = fileinfo.st_mtime;
   301     jft->date = fileinfo.st_mtime;
   282     jft->size = fileinfo.st_size;
   302     jft->size = fileinfo.st_size;
   283     jft->outfile = g_io_channel_new_file (filename, "r", NULL);
   303     jft->outfile = g_io_channel_new_file (filename, "r", &err);
   284     if (jft->outfile == NULL) {
   304     if (jft->outfile == NULL || err != NULL) {
   285       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Cannot open file %s", args[1]);
   305       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   306                    args[1]);
       
   307       g_error_free(err);
   286       return;
   308       return;
   287     }
   309     }
   288     
   310     
   289     g_io_channel_set_encoding(jft->outfile, NULL, NULL);
   311     g_io_channel_set_encoding(jft->outfile, NULL, &err);
       
   312     if (jft->outfile == NULL || err != NULL) {
       
   313       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
       
   314                    args[1]);
       
   315       g_error_free(err);
       
   316       return;
       
   317     }
   290     
   318     
   291     session_add_app(sess, "file", NS_JINGLE_APP_FT, jft);
   319     session_add_app(sess, "file", NS_JINGLE_APP_FT, jft);
   292 
   320 
   293     jingle_handle_app(sess, "file", NS_JINGLE_APP_FT, jft, recipientjid);
   321     jingle_handle_app(sess, "file", NS_JINGLE_APP_FT, jft, recipientjid);
   294 
   322 
   317 
   345 
   318   node2 = lm_message_node_add_child(node2, "file", NULL);
   346   node2 = lm_message_node_add_child(node2, "file", NULL);
   319 
   347 
   320   size = g_strdup_printf("%" G_GUINT64_FORMAT, jft->size);
   348   size = g_strdup_printf("%" G_GUINT64_FORMAT, jft->size);
   321   
   349   
   322   lm_message_node_set_attributes(node2, "xmlns", NS_SI_FT, "name", jft->name,
   350   lm_message_node_set_attributes(node2, "xmlns", NS_SI_FT,
   323                                  "size", size, NULL);
   351                                  "name", jft->name,
       
   352                                  "size", size,
       
   353                                  NULL);
   324   g_free(size);
   354   g_free(size);
   325   
   355   
   326   if (jft->hash != NULL)
   356   if (jft->hash != NULL)
   327     lm_message_node_set_attribute(node2, "hash", jft->hash);
   357     lm_message_node_set_attribute(node2, "hash", jft->hash);
   328 
   358 
   337 }
   367 }
   338 
   368 
   339 static void send_hash(gchar *sid, gchar *to, gchar *hash)
   369 static void send_hash(gchar *sid, gchar *to, gchar *hash)
   340 {
   370 {
   341   JingleAckHandle *ackhandle;
   371   JingleAckHandle *ackhandle;
   342   
   372   GError *err = NULL;
   343   LmMessage *r = lm_message_new_with_sub_type(to, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
   373   gboolean ret;
       
   374   
       
   375   LmMessage *r = lm_message_new_with_sub_type(to, LM_MESSAGE_TYPE_IQ,
       
   376                                               LM_MESSAGE_SUB_TYPE_SET);
   344   LmMessageNode *node = lm_message_get_node(r);
   377   LmMessageNode *node = lm_message_get_node(r);
   345   lm_message_node_add_child(node, "jingle", NULL);
   378   lm_message_node_add_child(node, "jingle", NULL);
   346   node = lm_message_node_get_child(node, "jingle");
   379   node = lm_message_node_get_child(node, "jingle");
   347   lm_message_node_set_attributes(node, "xmlns", NS_JINGLE, "sid", sid, "action", "session-info", NULL);
   380   lm_message_node_set_attributes(node, "xmlns", NS_JINGLE,
       
   381                                  "sid", sid,
       
   382                                  "action", "session-info",
       
   383                                  NULL);
   348   lm_message_node_add_child(node, "hash", hash);
   384   lm_message_node_add_child(node, "hash", hash);
   349   node = lm_message_node_get_child(node, "hash");
   385   node = lm_message_node_get_child(node, "hash");
   350   lm_message_node_set_attribute(node, "xmlns", NS_JINGLE_APP_FT_INFO);
   386   lm_message_node_set_attribute(node, "xmlns", NS_JINGLE_APP_FT_INFO);
   351   
   387   
   352   ackhandle = g_new0(JingleAckHandle, 1);
   388   ackhandle = g_new0(JingleAckHandle, 1);
   353   ackhandle->callback = NULL;
   389   ackhandle->callback = NULL;
   354   ackhandle->user_data = NULL;
   390   ackhandle->user_data = NULL;
   355   
   391   
   356   lm_connection_send_with_reply(lconnection, r,
   392   ret = lm_connection_send_with_reply(lconnection, r,
   357                                 jingle_new_ack_handler(ackhandle), NULL);
   393                                       jingle_new_ack_handler(ackhandle), &err);
       
   394   
       
   395   // It's not really a problem, but we must tell it!
       
   396   if (ret == FALSE || err != NULL) {
       
   397     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: cannot send hash: %s",
       
   398                  err->message);
       
   399     g_error_free(err);
       
   400   }
       
   401   
   358   lm_message_unref(r);
   402   lm_message_unref(r);
   359 }
   403 }
   360 
   404 
   361 static void send(session_content *sc)
   405 static void send(session_content *sc)
   362 {
   406 {
   363   JingleFT *jft;
   407   JingleFT *jft;
   364   gchar buf[JINGLE_FT_SIZE_READ];
   408   gchar buf[JINGLE_FT_SIZE_READ];
   365   gsize read;
   409   gsize read;
   366   GIOStatus status;
   410   GIOStatus status;
   367   int count = 0;
   411   int count = 0;
       
   412   GError *err = NULL;
       
   413   
   368   JingleSession *sess = session_find_by_sid(sc->sid, sc->from);
   414   JingleSession *sess = session_find_by_sid(sc->sid, sc->from);
   369   if (sess == NULL) {
   415   if (sess == NULL) {
   370     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: error before transfer");
   416     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: error before transfer");
   371     // We haven't LmMessage: jingle_send_iq_error(jn->message, "cancel", "item-not-found", "unknown-session");
   417     // We haven't LmMessage: jingle_send_iq_error(jn->message, "cancel", "item-not-found", "unknown-session");
   372     return;
   418     return;
   376   
   422   
   377   jft = (JingleFT*)sc2->description;
   423   jft = (JingleFT*)sc2->description;
   378   
   424   
   379   do {
   425   do {
   380     count++;
   426     count++;
   381     status = g_io_channel_read_chars(jft->outfile, (gchar*)buf, JINGLE_FT_SIZE_READ, &read, NULL);
   427     status = g_io_channel_read_chars(jft->outfile, (gchar*)buf,
       
   428                                      JINGLE_FT_SIZE_READ, &read, &err);
   382   } while (status == G_IO_STATUS_AGAIN && count < 10);
   429   } while (status == G_IO_STATUS_AGAIN && count < 10);
   383   
   430 
   384   if (status == G_IO_STATUS_AGAIN) {
   431   if (status == G_IO_STATUS_AGAIN) {
   385     // TODO: something better
   432     // TODO: something better
   386     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: file unavailable");
   433     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: file unavailable");
   387     return;
   434     return;
   388   }
   435   }
   389   
   436   
   390   if (status == G_IO_STATUS_ERROR) {
   437   if (status == G_IO_STATUS_ERROR || err != NULL) {
   391     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: an error occured");
   438     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s", err->message);
       
   439     g_error_free(err);
   392     return;
   440     return;
   393   }
   441   }
   394   
   442   
   395   if (status == G_IO_STATUS_NORMAL) {
   443   if (status == G_IO_STATUS_NORMAL) {
   396     g_checksum_update(jft->md5, (guchar*)buf, read);
   444     g_checksum_update(jft->md5, (guchar*)buf, read);
   398     handle_app_data(sc->sid, sc->from, sc->name, buf, read);
   446     handle_app_data(sc->sid, sc->from, sc->name, buf, read);
   399   }
   447   }
   400   
   448   
   401   if (status == G_IO_STATUS_EOF) {
   449   if (status == G_IO_STATUS_EOF) {
   402     handle_app_data(sc->sid, sc->from, sc->name, NULL, 0);
   450     handle_app_data(sc->sid, sc->from, sc->name, NULL, 0);
   403     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finish (%s)", jft->name);
   451     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finish (%s)",
       
   452                  jft->name);
   404     jft->hash = g_strdup(g_checksum_get_string(jft->md5));
   453     jft->hash = g_strdup(g_checksum_get_string(jft->md5));
   405     // Call a function to say state is ended
   454     // Call a function to say state is ended
   406     session_changestate_sessioncontent(sess, sc2->name, JINGLE_SESSION_STATE_ENDED);
   455     session_changestate_sessioncontent(sess, sc2->name, 
       
   456                                        JINGLE_SESSION_STATE_ENDED);
   407     // Send the hash
   457     // Send the hash
   408     send_hash(sess->sid, sess->to, jft->hash);
   458     send_hash(sess->sid, sess->to, jft->hash);
   409     g_checksum_free(jft->md5);
   459     g_checksum_free(jft->md5);
   410     
   460     
   411     if (!session_remove_sessioncontent(sess, sc2->name)) {
   461     if (!session_remove_sessioncontent(sess, sc2->name)) {
   439 
   489 
   440 // When we got a session-terminate
   490 // When we got a session-terminate
   441 static void stop(gconstpointer data)
   491 static void stop(gconstpointer data)
   442 {
   492 {
   443   JingleFT *jft = (JingleFT*)data;
   493   JingleFT *jft = (JingleFT*)data;
       
   494   GError *err = NULL;
       
   495   GIOStatus status;
       
   496   
       
   497   if (jft->outfile != NULL) {
       
   498     status = g_io_channel_flush(jft->outfile, &err);
       
   499     if (status != G_IO_STATUS_NORMAL || err != NULL) {
       
   500       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s",
       
   501                    err->message);
       
   502       g_error_free(err);
       
   503     }
       
   504     g_io_channel_unref(jft->outfile);
       
   505   }
   444 
   506 
   445   if (jft->hash != NULL && jft->md5 != NULL) {
   507   if (jft->hash != NULL && jft->md5 != NULL) {
   446     if (g_strcmp0(jft->hash, g_checksum_get_string(jft->md5))) {
   508     if (g_strcmp0(jft->hash, g_checksum_get_string(jft->md5))) {
   447       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File corrupt (%s)", jft->name);
   509       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File corrupt (%s)",
       
   510                    jft->name);
   448     } else {
   511     } else {
   449       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s) and verified", jft->name);
   512       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s)"
       
   513                    " and verified", jft->name);
   450     }
   514     }
   451   } else {
   515   } else {
   452     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s) but not verified", jft->name);
   516     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s)"
       
   517                  " but not verified", jft->name);
   453   }
   518   }
   454 
   519 
   455   g_checksum_free(jft->md5);
   520   g_checksum_free(jft->md5);
   456 
   521 
   457   if (jft->outfile != NULL) {
       
   458     g_io_channel_flush(jft->outfile, NULL);
       
   459 
       
   460     g_io_channel_unref(jft->outfile);
       
   461   }
       
   462 }
   522 }
   463 
   523 
   464 static void jingle_ft_init(void)
   524 static void jingle_ft_init(void)
   465 {
   525 {
   466   jingle_register_app(NS_JINGLE_APP_FT, &funcs, JINGLE_TRANSPORT_STREAMING);
   526   jingle_register_app(NS_JINGLE_APP_FT, &funcs, JINGLE_TRANSPORT_STREAMING);