jingle-ft/filetransfer.c
changeset 142 f513b0bc039a
parent 141 8bc73e965a07
child 143 cd97a18dd0b9
equal deleted inserted replaced
141:8bc73e965a07 142:f513b0bc039a
    50 static void start(session_content *sc);
    50 static void start(session_content *sc);
    51 static void send(session_content *sc);
    51 static void send(session_content *sc);
    52 static void stop(gconstpointer data);
    52 static void stop(gconstpointer data);
    53 static gchar* info(gconstpointer data);
    53 static gchar* info(gconstpointer data);
    54 
    54 
    55 static gboolean is_md5_hash(const gchar *hash);
       
    56 
    55 
    57 static void jingle_ft_init(void);
    56 static void jingle_ft_init(void);
    58 static void jingle_ft_uninit(void);
    57 static void jingle_ft_uninit(void);
    59 // Return must be free
    58 // Return must be free
    60 static gchar *_convert_size(guint64 size);
    59 static gchar *_convert_size(guint64 size);
    61 static int _next_index(void);
    60 static int _next_index(void);
    62 static void _free(JingleFT *jft);
    61 static void _free(JingleFT *jft);
    63 static gboolean _check_hash(const gchar *hash1, GChecksum *md5);
    62 static gboolean _check_hash(const gchar *hash1, GChecksum *md5);
       
    63 static gboolean _is_md5_hash(const gchar *hash);
       
    64 static void _jft_send(char **args);
       
    65 static void _jft_info(char **args);
       
    66 static void _jft_flush(char **args);
    64 
    67 
    65 const gchar *deps[] = { "jingle", NULL };
    68 const gchar *deps[] = { "jingle", NULL };
    66 
    69 
    67 static GSList *info_list = NULL;
    70 static GSList *info_list = NULL;
    68 static guint jft_cid = 0;
    71 static guint jft_cid = 0;
   175     g_free(ft);
   178     g_free(ft);
   176     return NULL;
   179     return NULL;
   177   }
   180   }
   178 
   181 
   179   // check if the md5 hash is valid ([a-fA-F0-9){32})
   182   // check if the md5 hash is valid ([a-fA-F0-9){32})
   180   if (ft->hash != NULL && (strlen(ft->hash) != 32 || !is_md5_hash(ft->hash))) {
   183   if (ft->hash != NULL && (strlen(ft->hash) != 32 || !_is_md5_hash(ft->hash))) {
   181     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
   184     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
   182                 "the offered file has an invalid hash");
   185                 "the offered file has an invalid hash");
   183     g_free(ft->name);
   186     g_free(ft->name);
   184     g_free(ft);
   187     g_free(ft);
   185     return NULL;
   188     return NULL;
   218 	return FALSE;
   221 	return FALSE;
   219   }
   222   }
   220   return FALSE;
   223   return FALSE;
   221 }
   224 }
   222 
   225 
   223 static gboolean is_md5_hash(const gchar *hash)
   226 static gboolean _is_md5_hash(const gchar *hash)
   224 {
   227 {
   225   int i = 0;
   228   int i = 0;
   226   for (i = 0; i < 32 && hash[i]; i++)
   229   for (i = 0; i < 32 && hash[i]; i++)
   227     if (!g_ascii_isxdigit(hash[i])) break;
   230     if (!g_ascii_isxdigit(hash[i])) break;
   228 
   231 
   301 {
   304 {
   302   static int a = 0;
   305   static int a = 0;
   303   return ++a;
   306   return ++a;
   304 }
   307 }
   305 
   308 
   306 static void do_sendfile(char *arg)
   309 static void _jft_info(char **args)
   307 {
   310 {
   308   char **args = split_arg(arg, 3, 0);
   311   GSList *el = info_list;
       
   312 
       
   313   if (!info_list)
       
   314     scr_LogPrint(LPRINT_LOGNORM, "JFT: no file");
       
   315 
       
   316   for (el = info_list; el; el = el->next) {
       
   317     JingleFTInfo *jftio = el->data;
       
   318     gchar *strsize = _convert_size(jftio->jft->size);
       
   319     const gchar *dir = (jftio->jft->dir == JINGLE_FT_INCOMING) ? "<==" : "-->";
       
   320     gfloat percent = (gfloat)jftio->jft->transmit/(gfloat)jftio->jft->size*100;
       
   321     const gchar *state = strstate[jftio->jft->state];
       
   322     const gchar *desc = jftio->jft->desc?jftio->jft->desc:"";
       
   323     const gchar *hash = "";
       
   324     if (jftio->jft->dir == JINGLE_FT_INCOMING &&
       
   325         jftio->jft->state == JINGLE_FT_ENDING) {
       
   326       if (_check_hash(jftio->jft->hash,jftio->jft->md5) == FALSE)
       
   327         hash = "corrupt";
       
   328       else
       
   329         hash = "checked";
       
   330     }
       
   331 
       
   332     scr_LogPrint(LPRINT_LOGNORM, "[%i]%s %s %s %.2f%%: %s %s %s", jftio->index, 
       
   333                  dir, jftio->jft->name, strsize, percent, desc, state, hash);
       
   334     g_free(strsize);
       
   335   }
       
   336 }
       
   337 
       
   338 static void _jft_flush(char **args)
       
   339 {
       
   340   GSList *el, *el2 = info_list;
       
   341   int count = 0;
       
   342   el = info_list;
       
   343   while (el) {
       
   344     JingleFTInfo *jftinf;
       
   345     jftinf = el->data;
       
   346     if (jftinf->jft->state == JINGLE_FT_ERROR ||
       
   347         jftinf->jft->state == JINGLE_FT_REJECT ||
       
   348         jftinf->jft->state == JINGLE_FT_ENDING) {
       
   349       count++;
       
   350       _free(jftinf->jft);
       
   351       info_list = g_slist_delete_link(info_list, el);
       
   352       if (info_list == NULL)
       
   353         break;
       
   354       el = el2;
       
   355       continue;
       
   356     }
       
   357     el2 = el;
       
   358     el = el->next;
       
   359   }
       
   360   scr_LogPrint(LPRINT_LOGNORM, "JFT: %i file%s removed", count, (count>1) ? "s" : "");
       
   361 }
       
   362 
       
   363 static void _jft_send(char **args)
       
   364 {
   309   gchar *filename;
   365   gchar *filename;
   310   struct stat fileinfo;
   366   struct stat fileinfo;
   311 
   367   
   312   if (!g_strcmp0(args[0], "send")) {
   368   if (!args[1]) {
   313 	  if (!args[1]) {
   369   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: give me a name!");
   314 		 scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: give me a name!");
   370   free_arg_lst(args);
   315 		 free_arg_lst(args);
   371     return;
   316 		 return;
   372   }
   317 	  }
   373 
   318 	  
   374   filename = expand_filename(args[1]); // expand ~ to HOME
   319 	  filename = expand_filename(args[1]); // expand ~ to HOME
   375 
   320 	  
   376   if (g_stat(filename, &fileinfo) != 0) {
   321 	  if (g_stat(filename, &fileinfo) != 0) {
   377     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: unable to stat %s",
   322 		 scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: unable to stat %s",
   378                  args[1]);
   323 		              args[1]);
   379     free_arg_lst(args);
   324 		 free_arg_lst(args);
   380     return;
   325 		 return;
   381   }
   326 	  }
   382 
   327 	  
   383   if (!S_ISREG(fileinfo.st_mode) && !S_ISLNK(fileinfo.st_mode)) {
   328 	  if (!S_ISREG(fileinfo.st_mode) && !S_ISLNK(fileinfo.st_mode)) {
   384     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File doesn't exist!");
   329 		 scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File doesn't exist!");
   385     free_arg_lst(args);
   330 		 free_arg_lst(args);
   386     return;
   331 		 return;
   387   }
   332 	  }
   388 
   333 	  
   389   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Trying to send %s",
   334 	  scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Trying to send %s",
   390                args[1]);
   335 		            args[1]);
   391 
   336 
   392   {
   337 	  {
   393     JingleSession *sess;
   338 		 JingleSession *sess;
   394     gchar *sid = jingle_generate_sid();
   339 		 gchar *sid = jingle_generate_sid();
   395     gchar *ressource, *recipientjid;
   340 		 gchar *ressource, *recipientjid;
   396     const gchar *namespaces[] = {NS_JINGLE, NS_JINGLE_APP_FT, NULL};
   341 		 const gchar *namespaces[] = {NS_JINGLE, NS_JINGLE_APP_FT, NULL};
   397     const gchar *myjid = g_strdup(lm_connection_get_jid(lconnection));
   342 		 const gchar *myjid = g_strdup(lm_connection_get_jid(lconnection));
   398     JingleFT *jft = g_new0(JingleFT, 1);
   343 		 JingleFT *jft = g_new0(JingleFT, 1);
   399     GError *err = NULL;
   344 		 GError *err = NULL;
   400 
   345 		 
   401     if (CURRENT_JID == NULL) { // CURRENT_JID = the jid of the user which has focus
   346 		 if (CURRENT_JID == NULL) { // CURRENT_JID = the jid of the user which has focus
   402       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Please, choose a valid JID in the roster");
   347 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Please, choose a valid JID in the roster");
   403       free_arg_lst(args);
   348 		   free_arg_lst(args);
   404       return;
   349 		   return;
   405     }
   350 		 }
   406     ressource = jingle_find_compatible_res(CURRENT_JID, namespaces);
   351 		 ressource = jingle_find_compatible_res(CURRENT_JID, namespaces);
   407     if (ressource == NULL) {
   352 		 if (ressource == NULL) {
   408       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Cannot send file, because there is no ressource available");
   353 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Cannot send file, because there is no ressource available");
   409       free_arg_lst(args);
   354 		   free_arg_lst(args);
   410       return;
   355 		   return;
   411     }
   356 		 }
   412 
   357 		 
   413     recipientjid = g_strdup_printf("%s/%s", CURRENT_JID, ressource);
   358 		 recipientjid = g_strdup_printf("%s/%s", CURRENT_JID, ressource);
   414 
   359 
   415     sess = session_new(sid, myjid, recipientjid, JINGLE_SESSION_OUTGOING);
   360 		 sess = session_new(sid, myjid, recipientjid, JINGLE_SESSION_OUTGOING);
   416     session_add_content(sess, "file", JINGLE_SESSION_STATE_PENDING);
   361 		 session_add_content(sess, "file", JINGLE_SESSION_STATE_PENDING);
   417 
   362 
   418     jft->desc = g_strdup(args[1]);
   363 		 jft->desc = g_strdup(args[1]);
   419     jft->type = JINGLE_FT_OFFER;
   364 		 jft->type = JINGLE_FT_OFFER;
   420     jft->name = g_path_get_basename(filename);
   365 		 jft->name = g_path_get_basename(filename);
   421     jft->date = fileinfo.st_mtime;
   366 		 jft->date = fileinfo.st_mtime;
   422     jft->size = fileinfo.st_size;
   367 		 jft->size = fileinfo.st_size;
   423     jft->transmit = 0;
   368 		 jft->transmit = 0;
   424     jft->state = JINGLE_FT_PENDING;
   369 		 jft->state = JINGLE_FT_PENDING;
   425     jft->dir = JINGLE_FT_OUTGOING;
   370 		 jft->dir = JINGLE_FT_OUTGOING;
   426     jft->outfile = g_io_channel_new_file (filename, "r", &err);
   371 		 jft->outfile = g_io_channel_new_file (filename, "r", &err);
   427     if (jft->outfile == NULL || err != NULL) {
   372 		 if (jft->outfile == NULL || err != NULL) {
   428       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   373 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   429                    args[1]);
   374 		                args[1]);
   430       g_error_free(err);
   375 		   g_error_free(err);
   431       free_arg_lst(args);
   376 		   free_arg_lst(args);
   432       return;
   377 		   return;
   433     }
   378 		 }
   434 
   379 		 
   435     g_io_channel_set_encoding(jft->outfile, NULL, &err);
   380 		 g_io_channel_set_encoding(jft->outfile, NULL, &err);
   436     if (jft->outfile == NULL || err != NULL) {
   381 		 if (jft->outfile == NULL || err != NULL) {
   437       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   382 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   438                    args[1]);
   383 		                args[1]);
   439       g_error_free(err);
   384 		   g_error_free(err);
   440       free_arg_lst(args);
   385 		   free_arg_lst(args);
   441       return;
   386 		   return;
   442     }
   387 		 }
   443 
   388 		 
   444     session_add_app(sess, "file", NS_JINGLE_APP_FT, jft);
   389 		 session_add_app(sess, "file", NS_JINGLE_APP_FT, jft);
   445 
   390 
   446     {
   391 		 {
   447       JingleFTInfo *jfti = g_new0(JingleFTInfo, 1);
   392 		   JingleFTInfo *jfti = g_new0(JingleFTInfo, 1);
   448       jfti->index = _next_index();
   393 		   jfti->index = _next_index();
   449       jfti->jft = jft;
   394 		   jfti->jft = jft;
   450       info_list = g_slist_append(info_list, jfti);
   395 		   info_list = g_slist_append(info_list, jfti);
   451     }
   396 		 }
   452 
   397 		 
   453     jingle_handle_app(sess, "file", NS_JINGLE_APP_FT, jft, recipientjid);
   398 		 jingle_handle_app(sess, "file", NS_JINGLE_APP_FT, jft, recipientjid);
   454 
   399 
   455     g_free(ressource);
   400 		 g_free(ressource);
   456     g_free(sid);
   401 		 g_free(sid);
   457   }
   402 	  }
   458 }
   403   } else if (!g_strcmp0(args[0], "info")) {
   459 
   404     GSList *el = info_list;
   460 static void do_sendfile(char *arg)
   405     
   461 {
   406     if (!info_list)
   462   char **args = split_arg(arg, 3, 0);
   407       scr_LogPrint(LPRINT_LOGNORM, "JFT: no file");
   463 
   408 
   464   if (!g_strcmp0(args[0], "send"))
   409     for (el = info_list; el; el = el->next) {
   465     _jft_send(args);
   410       JingleFTInfo *jftio = el->data;
   466   else if (!g_strcmp0(args[0], "info"))
   411       gchar *strsize = _convert_size(jftio->jft->size);
   467     _jft_info(args);
   412       const gchar *dir = (jftio->jft->dir == JINGLE_FT_INCOMING) ? "<==" : "-->";
   468   else if (!g_strcmp0(args[0], "flush"))
   413       gfloat percent = (gfloat)jftio->jft->transmit/(gfloat)jftio->jft->size*100;
   469     _jft_flush(args);
   414       const gchar *state = strstate[jftio->jft->state];
   470   else
   415       const gchar *desc = jftio->jft->desc?jftio->jft->desc:"";
       
   416       const gchar *hash = "";
       
   417       if (jftio->jft->dir == JINGLE_FT_INCOMING &&
       
   418           jftio->jft->state == JINGLE_FT_ENDING) {
       
   419         if (_check_hash(jftio->jft->hash,jftio->jft->md5) == FALSE)
       
   420           hash = "corrupt";
       
   421         else
       
   422           hash = "checked";
       
   423       }
       
   424       
       
   425       scr_LogPrint(LPRINT_LOGNORM, "[%i]%s %s %s %.2f%%: %s %s %s", jftio->index, 
       
   426                    dir, jftio->jft->name, strsize, percent, desc, state, hash);
       
   427       g_free(strsize);
       
   428     }
       
   429   } else if (!g_strcmp0(args[0], "flush")) {
       
   430     GSList *el, *el2 = info_list;
       
   431     int count = 0;
       
   432     el = info_list;
       
   433     while (el) {
       
   434       JingleFTInfo *jftinf;
       
   435       jftinf = el->data;
       
   436       if (jftinf->jft->state == JINGLE_FT_ERROR ||
       
   437           jftinf->jft->state == JINGLE_FT_REJECT ||
       
   438           jftinf->jft->state == JINGLE_FT_ENDING) {
       
   439         count++;
       
   440         _free(jftinf->jft);
       
   441         info_list = g_slist_delete_link(info_list, el);
       
   442         if (info_list == NULL)
       
   443           break;
       
   444         el = el2;
       
   445         continue;
       
   446       }
       
   447       el2 = el;
       
   448       el = el->next;
       
   449     }
       
   450     scr_LogPrint(LPRINT_LOGNORM, "JFT: %i file%s removed", count, (count>1) ? "s" : "");
       
   451   } else {
       
   452     scr_LogPrint(LPRINT_LOGNORM, "/jft: %s is not a correct option.", args[1]);
   471     scr_LogPrint(LPRINT_LOGNORM, "/jft: %s is not a correct option.", args[1]);
   453   }
   472 
   454   
       
   455   free_arg_lst(args);
   473   free_arg_lst(args);
   456 }
   474 }
   457 
   475 
   458 static void _free(JingleFT *jft)
   476 static void _free(JingleFT *jft)
   459 {
   477 {