jingle-filetransfer/filetransfer.c
changeset 133 361d8577ebd1
parent 131 943c3f938cb4
child 134 8c98308c139d
equal deleted inserted replaced
132:4fef4ced1e97 133:361d8577ebd1
    57 
    57 
    58 static void jingle_ft_init(void);
    58 static void jingle_ft_init(void);
    59 static void jingle_ft_uninit(void);
    59 static void jingle_ft_uninit(void);
    60 // Return must be free
    60 // Return must be free
    61 static gchar *_convert_size(guint64 size);
    61 static gchar *_convert_size(guint64 size);
       
    62 static int _next_index(void);
       
    63 static void _free(gconstpointer data);
    62 
    64 
    63 const gchar *deps[] = { "jingle", NULL };
    65 const gchar *deps[] = { "jingle", NULL };
    64 
    66 
    65 static GSList *info_list = NULL;
    67 static GSList *info_list = NULL;
    66 static guint jft_cid = 0;
    68 static guint jft_cid = 0;
       
    69 
       
    70 const gchar* strstate[] = {
       
    71   "PENDING",
       
    72   "STARTING",
       
    73   "ENDING",
       
    74   "REJECT",
       
    75   "ERROR"
       
    76 };
    67 
    77 
    68 static JingleAppFuncs funcs = {
    78 static JingleAppFuncs funcs = {
    69   .check        = check,
    79   .check        = check,
    70   .handle       = handle,
    80   .handle       = handle,
    71   .tomessage    = tomessage,
    81   .tomessage    = tomessage,
   120   datestr  = lm_message_node_get_attribute(node, "date");
   130   datestr  = lm_message_node_get_attribute(node, "date");
   121   ft->hash = (gchar *) lm_message_node_get_attribute(node, "hash");
   131   ft->hash = (gchar *) lm_message_node_get_attribute(node, "hash");
   122   ft->name = (gchar *) lm_message_node_get_attribute(node, "name");
   132   ft->name = (gchar *) lm_message_node_get_attribute(node, "name");
   123   sizestr  = lm_message_node_get_attribute(node, "size");
   133   sizestr  = lm_message_node_get_attribute(node, "size");
   124   ft->transmit = 0;
   134   ft->transmit = 0;
   125   
       
   126   ft->dir = JINGLE_FT_INCOMING;
   135   ft->dir = JINGLE_FT_INCOMING;
   127   
   136   
   128   if (!ft->name || !sizestr) {
   137   if (!ft->name || !sizestr) {
   129     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
   138     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
   130                 "an attribute of the file element is missing");
   139                 "an attribute of the file element is missing");
   166     g_free(ft->name);
   175     g_free(ft->name);
   167     g_free(ft);
   176     g_free(ft);
   168     return NULL;
   177     return NULL;
   169   }
   178   }
   170   ft->hash = g_strndup(ft->hash, 32);
   179   ft->hash = g_strndup(ft->hash, 32);
       
   180 
       
   181   {
       
   182     JingleFTInfo *jfti = g_new0(JingleFTInfo, 1);
       
   183     jfti->index = _next_index();
       
   184     jfti->jft = ft;
       
   185     info_list = g_slist_append(info_list, jfti);
       
   186   }
   171 
   187 
   172   return (gconstpointer) ft;
   188   return (gconstpointer) ft;
   173 }
   189 }
   174 
   190 
   175 static gboolean handle(JingleAction action, gconstpointer data,
   191 static gboolean handle(JingleAction action, gconstpointer data,
   224                    jft->name);
   240                    jft->name);
   225     //TODO: propagate the GError ?
   241     //TODO: propagate the GError ?
   226       g_error_free(err);
   242       g_error_free(err);
   227       return FALSE;
   243       return FALSE;
   228 	}
   244 	}
       
   245 	jft->state = JINGLE_FT_STARTING;
   229 	status = g_io_channel_set_encoding(jft->outfile, NULL, &err);
   246 	status = g_io_channel_set_encoding(jft->outfile, NULL, &err);
   230 	if (status != G_IO_STATUS_NORMAL || err != NULL) {
   247 	if (status != G_IO_STATUS_NORMAL || err != NULL) {
   231      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   248      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   232                   jft->name);
   249                   jft->name);
   233      g_error_free(err);
   250      g_error_free(err);
   234      return FALSE;
   251      return FALSE;
   235    }
   252    }
   236   }
   253   }
   237 
   254   
       
   255   jft->state = JINGLE_FT_STARTING;
       
   256 	
   238   status = g_io_channel_write_chars(jft->outfile, data, (gssize) len,
   257   status = g_io_channel_write_chars(jft->outfile, data, (gssize) len,
   239                                     &bytes_written, &err);
   258                                     &bytes_written, &err);
   240   if (status != G_IO_STATUS_NORMAL || err != NULL) {
   259   if (status != G_IO_STATUS_NORMAL || err != NULL) {
   241      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   260      scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   242                   jft->name);
   261                   jft->name);
   259   jft->transmit += len;
   278   jft->transmit += len;
   260   return TRUE;
   279   return TRUE;
   261 }
   280 }
   262 
   281 
   263 
   282 
   264 static int _next_index()
   283 static int _next_index(void)
   265 {
   284 {
   266   static int a = 0;
   285   static int a = 0;
   267   return a++;
   286   return a++;
   268 }
   287 }
   269 
   288 
   294 		 free_arg_lst(args);
   313 		 free_arg_lst(args);
   295 		 return;
   314 		 return;
   296 	  }
   315 	  }
   297 	  
   316 	  
   298 	  scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Trying to send %s",
   317 	  scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Trying to send %s",
   299 		            args[0]);
   318 		            args[1]);
   300 
   319 
   301 	  {
   320 	  {
   302 		 JingleSession *sess;
   321 		 JingleSession *sess;
   303 		 gchar *sid = jingle_generate_sid();
   322 		 gchar *sid = jingle_generate_sid();
   304 		 gchar *ressource, *recipientjid;
   323 		 gchar *ressource, *recipientjid;
   328 		 jft->type = JINGLE_FT_OFFER;
   347 		 jft->type = JINGLE_FT_OFFER;
   329 		 jft->name = g_path_get_basename(filename);
   348 		 jft->name = g_path_get_basename(filename);
   330 		 jft->date = fileinfo.st_mtime;
   349 		 jft->date = fileinfo.st_mtime;
   331 		 jft->size = fileinfo.st_size;
   350 		 jft->size = fileinfo.st_size;
   332 		 jft->transmit = 0;
   351 		 jft->transmit = 0;
       
   352 		 jft->state = JINGLE_FT_PENDING;
   333 		 jft->dir = JINGLE_FT_OUTGOING;
   353 		 jft->dir = JINGLE_FT_OUTGOING;
   334 		 jft->outfile = g_io_channel_new_file (filename, "r", &err);
   354 		 jft->outfile = g_io_channel_new_file (filename, "r", &err);
   335 		 if (jft->outfile == NULL || err != NULL) {
   355 		 if (jft->outfile == NULL || err != NULL) {
   336 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   356 		   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s %s", err->message,
   337 		                args[1]);
   357 		                args[1]);
   368     
   388     
   369     if (!info_list)
   389     if (!info_list)
   370       scr_LogPrint(LPRINT_LOGNORM, "JFT: no file");
   390       scr_LogPrint(LPRINT_LOGNORM, "JFT: no file");
   371 
   391 
   372     for (el = info_list; el; el = el->next) {
   392     for (el = info_list; el; el = el->next) {
   373       JingleFTInfo* jftio = el->data;
   393       JingleFTInfo *jftio = el->data;
   374       gchar *strsize = _convert_size(jftio->jft->size);
   394       gchar *strsize = _convert_size(jftio->jft->size);
   375       scr_LogPrint(LPRINT_LOGNORM, "[%i]%s %s %s %.2f%%: %s", jftio->index, 
   395       scr_LogPrint(LPRINT_LOGNORM, "[%i]%s %s %s %.2f%%: %s %s", jftio->index, 
   376                    (jftio->jft->dir == JINGLE_FT_INCOMING)?"<==":"-->",
   396                    (jftio->jft->dir == JINGLE_FT_INCOMING)?"<==":"-->",
   377                    jftio->jft->name, strsize,
   397                    jftio->jft->name, strsize,
   378                    (gfloat)jftio->jft->transmit/(gfloat)jftio->jft->size * 100,
   398                    (gfloat)jftio->jft->transmit/(gfloat)jftio->jft->size * 100,
   379                    jftio->jft->desc);
   399                    jftio->jft->desc?jftio->jft->desc:"",
       
   400                    strstate[jftio->jft->state]);
   380       g_free(strsize);
   401       g_free(strsize);
   381     }
   402     }
   382   
   403   } else if (!g_strcmp0(args[0], "flush")) {
       
   404     GSList *el, *el2 = NULL;
       
   405     int count = 0;
       
   406     for (el = info_list; el; el = el -> next) {
       
   407       JingleFTInfo *jftio = el->data;
       
   408       if (jftio->jft->state == JINGLE_FT_ERROR ||
       
   409           jftio->jft->state == JINGLE_FT_REJECT ||
       
   410           jftio->jft->state == JINGLE_FT_ENDING) {
       
   411         g_slist_free_1(el2);
       
   412         count++;
       
   413         _free(jftio->jft);
       
   414         info_list = g_slist_remove(info_list, jftio);
       
   415         el2 = el;
       
   416       }
       
   417     }
       
   418     g_slist_free_1(el2);
       
   419     scr_LogPrint(LPRINT_LOGNORM, "JFT: %i files removed", count);
       
   420   } else {
       
   421     scr_LogPrint(LPRINT_LOGNORM, "/jft: %s is not a correct option.", args[1]);
   383   }
   422   }
   384   
   423   
   385   free_arg_lst(args);
   424   free_arg_lst(args);
       
   425 }
       
   426 
       
   427 static void _free(gconstpointer data)
       
   428 {
       
   429   JingleFT *jft = (JingleFT *)data;
       
   430   g_free(jft->hash);
       
   431   g_free(jft->name);
       
   432   g_free(jft->desc);
       
   433   g_io_channel_unref(jft->outfile);
       
   434   if (jft->dir == JINGLE_FT_INCOMING)
       
   435     g_checksum_free(jft->md5);
       
   436   g_free(jft);
   386 }
   437 }
   387 
   438 
   388 static void tomessage(gconstpointer data, LmMessageNode *node)
   439 static void tomessage(gconstpointer data, LmMessageNode *node)
   389 {
   440 {
   390   JingleFT *jft = (JingleFT*) data;
   441   JingleFT *jft = (JingleFT*) data;
   422     lm_message_node_add_child(node2, "desc", jft->desc);
   473     lm_message_node_add_child(node2, "desc", jft->desc);
   423 
   474 
   424   //if (jft->data != 0)
   475   //if (jft->data != 0)
   425 }
   476 }
   426 
   477 
   427 static void send_hash(gchar *sid, gchar *to, gchar *hash)
   478 static void send_hash(const gchar *sid, const gchar *to, const gchar *hash)
   428 {
   479 {
   429   JingleAckHandle *ackhandle;
   480   JingleAckHandle *ackhandle;
   430   GError *err = NULL;
   481   GError *err = NULL;
   431   gboolean ret;
   482   gboolean ret;
   432   
   483   
   538   }
   589   }
   539   
   590   
   540   SessionContent *sc2 = session_find_sessioncontent(sess, sc->name);
   591   SessionContent *sc2 = session_find_sessioncontent(sess, sc->name);
   541 
   592 
   542   jft = (JingleFT*)sc2->description;
   593   jft = (JingleFT*)sc2->description;
   543   
   594   jft->state = JINGLE_FT_STARTING;
   544   jft->md5 = g_checksum_new(G_CHECKSUM_MD5);
   595   jft->md5 = g_checksum_new(G_CHECKSUM_MD5);
   545   
   596   
   546   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Transfer start (%s)",
   597   scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: Transfer start (%s)",
   547                jft->name);
   598                jft->name);
   548 
   599 
   554 {
   605 {
   555   JingleFT *jft = (JingleFT*)data;
   606   JingleFT *jft = (JingleFT*)data;
   556   GError *err = NULL;
   607   GError *err = NULL;
   557   GIOStatus status;
   608   GIOStatus status;
   558   
   609   
       
   610   jft->state = JINGLE_FT_ENDING;
   559   if (jft->outfile != NULL) {
   611   if (jft->outfile != NULL) {
   560     status = g_io_channel_flush(jft->outfile, &err);
   612     status = g_io_channel_shutdown(jft->outfile, TRUE, &err);
   561     if (status != G_IO_STATUS_NORMAL || err != NULL) {
   613     if (status != G_IO_STATUS_NORMAL || err != NULL) {
   562       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s",
   614       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: %s",
   563                    err->message);
   615                    err->message);
   564       g_error_free(err);
   616       g_error_free(err);
   565     }
   617     }
   566     g_io_channel_unref(jft->outfile);
       
   567   }
   618   }
   568 
   619 
   569   if (jft->hash != NULL && jft->md5 != NULL) {
   620   if (jft->hash != NULL && jft->md5 != NULL) {
   570     if (g_strcmp0(jft->hash, g_checksum_get_string(jft->md5))) {
   621     if (g_strcmp0(jft->hash, g_checksum_get_string(jft->md5))) {
   571       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File corrupt (%s)",
   622       scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: File corrupt (%s)",
   576     }
   627     }
   577   } else {
   628   } else {
   578     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s)"
   629     scr_LogPrint(LPRINT_LOGNORM, "Jingle File Transfer: transfer finished (%s)"
   579                  " but not verified", jft->name);
   630                  " but not verified", jft->name);
   580   }
   631   }
   581 
       
   582   g_checksum_free(jft->md5);
       
   583 
       
   584 }
   632 }
   585 
   633 
   586 static gchar *_convert_size(guint64 size)
   634 static gchar *_convert_size(guint64 size)
   587 {
   635 {
   588   gchar *strsize;
   636   gchar *strsize;
   617   jft_cid = compl_new_category();
   665   jft_cid = compl_new_category();
   618   if (jft_cid) {
   666   if (jft_cid) {
   619     compl_add_category_word(jft_cid, "send");
   667     compl_add_category_word(jft_cid, "send");
   620     //compl_add_category_word(jft_cid, "request");
   668     //compl_add_category_word(jft_cid, "request");
   621     compl_add_category_word(jft_cid, "info");
   669     compl_add_category_word(jft_cid, "info");
       
   670     compl_add_category_word(jft_cid, "flush");
   622   }
   671   }
   623   /* Add command */
   672   /* Add command */
   624   cmd_add("jft", "Manage file transfer", jft_cid, 0, do_sendfile, NULL);
   673   cmd_add("jft", "Manage file transfer", jft_cid, 0, do_sendfile, NULL);
   625 }
   674 }
   626 
   675 
   627 static void jingle_ft_uninit(void)
   676 static void jingle_ft_uninit(void)
   628 {
   677 {
       
   678   g_slist_free(info_list);
   629   xmpp_del_feature(NS_JINGLE_APP_FT);
   679   xmpp_del_feature(NS_JINGLE_APP_FT);
   630   jingle_unregister_app(NS_JINGLE_APP_FT);
   680   jingle_unregister_app(NS_JINGLE_APP_FT);
   631   cmd_del("file");
   681   cmd_del("file");
   632   if (jft_cid)
   682   if (jft_cid)
   633     compl_del_category(jft_cid);
   683     compl_del_category(jft_cid);