Home | History | Annotate | Download | only in examples
      1 /**
      2  * \file sendtr.c
      3  * Example program to send a music track to a device.
      4  * This program is derived from the exact equivalent in libnjb.
      5  * based on Enrique Jorreto Ledesma's work on the original program by
      6  * Shaun Jackman and Linus Walleij.
      7  *
      8  * Copyright (C) 2003-2010 Linus Walleij <triad (at) df.lth.se>
      9  * Copyright (C) 2003-2005 Shaun Jackman
     10  * Copyright (C) 2003-2005 Enrique Jorrete Ledesma
     11  * Copyright (C) 2006 Chris A. Debenham <chris (at) adebenham.com>
     12  * Copyright (C) 2008 Nicolas Pennequin <nicolas.pennequin (at) free.fr>
     13  * Copyright (C) 2008 Joseph Nahmias <joe (at) nahmias.net>
     14  *
     15  * This library is free software; you can redistribute it and/or
     16  * modify it under the terms of the GNU Lesser General Public
     17  * License as published by the Free Software Foundation; either
     18  * version 2 of the License, or (at your option) any later version.
     19  *
     20  * This library is distributed in the hope that it will be useful,
     21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23  * Lesser General Public License for more details.
     24  *
     25  * You should have received a copy of the GNU Lesser General Public
     26  * License along with this library; if not, write to the
     27  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     28  * Boston, MA 02111-1307, USA.
     29  */
     30 
     31 #include <stdlib.h>
     32 #include <limits.h>
     33 #include <string.h>
     34 #include <libgen.h>
     35 #include <sys/stat.h>
     36 #include <sys/types.h>
     37 #include <fcntl.h>
     38 #ifdef HAVE_LANGINFO_H
     39 #include <langinfo.h>
     40 #endif
     41 
     42 #include "config.h"
     43 #include "common.h"
     44 #include "util.h"
     45 #include "connect.h"
     46 #include "libmtp.h"
     47 #include "pathutils.h"
     48 
     49 extern LIBMTP_folder_t *folders;
     50 extern LIBMTP_file_t *files;
     51 extern LIBMTP_mtpdevice_t *device;
     52 
     53 void sendtrack_usage (void)
     54 {
     55   fprintf(stderr, "usage: sendtr [ -D debuglvl ] [ -q ]\n");
     56   fprintf(stderr, "-t <title> -a <artist> -A <Album artist> -w <writer or composer>\n");
     57   fprintf(stderr, "    -l <album> -c <codec> -g <genre> -n <track number> -y <year>\n");
     58   fprintf(stderr, "       -d <duration in seconds> -s <storage_id> <local path> <remote path>\n");
     59   fprintf(stderr, "(-q means the program will not ask for missing information.)\n");
     60 }
     61 
     62 static char *prompt (const char *prompt, char *buffer, size_t bufsz, int required)
     63 {
     64   char *cp, *bp;
     65 
     66   while (1) {
     67     fprintf(stdout, "%s> ", prompt);
     68     if ( fgets(buffer, bufsz, stdin) == NULL ) {
     69       if (ferror(stdin)) {
     70 	perror("fgets");
     71       } else {
     72 	fprintf(stderr, "EOF on stdin\n");
     73       }
     74       return NULL;
     75     }
     76 
     77     cp = strrchr(buffer, '\n');
     78     if ( cp != NULL ) *cp = '\0';
     79 
     80     bp = buffer;
     81     while ( bp != cp ) {
     82       if ( *bp != ' ' && *bp != '\t' ) return bp;
     83       bp++;
     84     }
     85 
     86     if (! required) return bp;
     87   }
     88 }
     89 
     90 static int add_track_to_album(LIBMTP_album_t *albuminfo, LIBMTP_track_t *trackmeta)
     91 {
     92   LIBMTP_album_t *album;
     93   LIBMTP_album_t *album_orig;
     94   LIBMTP_album_t *found_album = NULL;
     95   int ret;
     96 
     97   /* Look for the album */
     98   album = LIBMTP_Get_Album_List(device);
     99   album_orig = album;
    100   while(album != NULL) {
    101     if ((album->name != NULL &&
    102 	album->artist != NULL &&
    103 	!strcmp(album->name, albuminfo->name) &&
    104 	!strcmp(album->artist, albuminfo->artist)) ||
    105 	  (album->name != NULL &&
    106 	album->composer != NULL &&
    107 	!strcmp(album->name, albuminfo->name) &&
    108 	!strcmp(album->composer, albuminfo->composer))) {
    109       /* Disconnect this album for later use */
    110       found_album = album;
    111       album = album->next;
    112       found_album->next = NULL;
    113     } else {
    114       album = album->next;
    115     }
    116   }
    117 
    118   if (found_album == NULL) {
    119     printf("Could not find Album. Retrying with only Album name\n");
    120     album = album_orig;
    121     while(album != NULL) {
    122       if ((album->name != NULL) &&
    123           !strcmp(album->name, albuminfo->name) ){
    124         /* Disconnect this album for later use */
    125         found_album = album;
    126         album = album->next;
    127         found_album->next = NULL;
    128       } else {
    129         album = album->next;
    130       }
    131     }
    132   }
    133 
    134   if (found_album != NULL) {
    135     uint32_t *tracks;
    136 
    137     tracks = (uint32_t *)malloc((found_album->no_tracks+1) * sizeof(uint32_t));
    138     printf("Album \"%s\" found: updating...\n", found_album->name);
    139     if (!tracks) {
    140       printf("failed malloc in add_track_to_album()\n");
    141       return 1;
    142     }
    143     found_album->no_tracks++;
    144     if (found_album->tracks != NULL) {
    145       memcpy(tracks, found_album->tracks, found_album->no_tracks * sizeof(uint32_t));
    146       free(found_album->tracks);
    147     }
    148     tracks[found_album->no_tracks-1] = trackmeta->item_id;
    149     found_album->tracks = tracks;
    150     ret = LIBMTP_Update_Album(device, found_album);
    151   } else {
    152     uint32_t *trackid;
    153 
    154     trackid = (uint32_t *)malloc(sizeof(uint32_t));
    155     *trackid = trackmeta->item_id;
    156     albuminfo->tracks = trackid;
    157     albuminfo->no_tracks = 1;
    158     albuminfo->storage_id = trackmeta->storage_id;
    159     printf("Album doesn't exist: creating...\n");
    160     ret = LIBMTP_Create_New_Album(device, albuminfo);
    161     /* albuminfo will be destroyed later by caller */
    162   }
    163 
    164   /* Delete the earlier retrieved Album list */
    165   album=album_orig;
    166   while(album!=NULL){
    167     LIBMTP_album_t *tmp;
    168 
    169     tmp = album;
    170     album = album->next;
    171     LIBMTP_destroy_album_t(tmp);
    172   }
    173 
    174   if (ret != 0) {
    175     printf("Error creating or updating album.\n");
    176     printf("(This could be due to that your device does not support albums.)\n");
    177     LIBMTP_Dump_Errorstack(device);
    178     LIBMTP_Clear_Errorstack(device);
    179   } else {
    180     printf("success!\n");
    181   }
    182   return ret;
    183 }
    184 
    185 int sendtrack_function(char * from_path, char * to_path, char *partist, char *palbumartist, char *ptitle, char *pgenre, char *palbum, char *pcomposer, uint16_t tracknum, uint16_t length, uint16_t year, uint32_t storageid, uint16_t quiet)
    186 {
    187   char *filename, *parent;
    188   char artist[80], albumartist[80], title[80], genre[80], album[80], composer[80];
    189   char *to_path_copy = NULL;
    190   char num[80];
    191   uint64_t filesize;
    192   uint32_t parent_id = 0;
    193   struct stat sb;
    194   LIBMTP_track_t *trackmeta;
    195   LIBMTP_album_t *albuminfo;
    196   int ret;
    197 
    198   printf("Sending track %s to %s\n", from_path, to_path);
    199 
    200   to_path_copy = strdup(to_path);
    201   parent = dirname(to_path_copy);
    202   parent_id = parse_path (parent,files,folders);
    203   if (parent_id == -1) {
    204     free (to_path_copy);
    205     printf("Parent folder could not be found, skipping\n");
    206     return 1;
    207   }
    208   strcpy (to_path_copy,to_path);
    209   filename = basename(to_path_copy);
    210 
    211   if (stat(from_path, &sb) == -1) {
    212     fprintf(stderr, "%s: ", from_path);
    213     perror("stat");
    214     free (to_path_copy);
    215     return 1;
    216   }
    217 
    218   if (!S_ISREG(sb.st_mode)) {
    219     free (to_path_copy);
    220     return 0;
    221   }
    222 
    223   filesize = sb.st_size;
    224 
    225   trackmeta = LIBMTP_new_track_t();
    226   trackmeta->filetype = find_filetype (from_path);
    227   if (!LIBMTP_FILETYPE_IS_TRACK(trackmeta->filetype)) {
    228     printf("Not a valid track codec: \"%s\"\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype));
    229     LIBMTP_destroy_track_t(trackmeta);
    230     free (to_path_copy);
    231     return 1;
    232   }
    233 
    234   if ((ptitle == NULL) && (quiet == 0)) {
    235     if ( (ptitle = prompt("Title", title, 80, 0)) != NULL )
    236       if (!strlen(ptitle)) ptitle = NULL;
    237   }
    238 
    239   if ((palbum == NULL) && (quiet == 0)) {
    240     if ( (palbum = prompt("Album", album, 80, 0)) != NULL )
    241       if (!strlen(palbum)) palbum = NULL;
    242   }
    243 
    244   if ((palbumartist == NULL) && (quiet == 0)) {
    245     if ( (palbumartist = prompt("Album artist", albumartist, 80, 0)) != NULL )
    246       if (!strlen(palbumartist)) palbumartist = NULL;
    247   }
    248 
    249   if ((partist == NULL) && (quiet == 0)) {
    250     if ( (partist = prompt("Artist", artist, 80, 0)) != NULL )
    251       if (!strlen(partist)) partist = NULL;
    252   }
    253 
    254   if ((pcomposer == NULL) && (quiet == 0)) {
    255     if ( (pcomposer = prompt("Writer or Composer", composer, 80, 0)) != NULL )
    256       if (!strlen(pcomposer)) pcomposer = NULL;
    257   }
    258 
    259   if ((pgenre == NULL) && (quiet == 0)) {
    260     if ( (pgenre = prompt("Genre", genre, 80, 0)) != NULL )
    261       if (!strlen(pgenre)) pgenre = NULL;
    262   }
    263 
    264   if ((tracknum == 0) && (quiet == 0)) {
    265     char *pnum;
    266     if ( (pnum = prompt("Track number", num, 80, 0)) == NULL )
    267       tracknum = 0;
    268     else
    269       tracknum = strtoul(pnum, 0, 10);
    270   }
    271 
    272   if ((year == 0) && (quiet == 0)) {
    273     char *pnum;
    274     if ( (pnum = prompt("Year", num, 80, 0)) == NULL )
    275       year = 0;
    276     else
    277       year = strtoul(pnum, 0, 10);
    278   }
    279 
    280   if ((length == 0) && (quiet == 0)) {
    281     char *pnum;
    282     if ( (pnum = prompt("Length", num, 80, 0)) == NULL )
    283       length = 0;
    284     else
    285       length = strtoul(pnum, 0, 10);
    286   }
    287 
    288   printf("Sending track:\n");
    289   printf("Codec:     %s\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype));
    290   if (ptitle) {
    291     printf("Title:     %s\n", ptitle);
    292     trackmeta->title = strdup(ptitle);
    293   }
    294 
    295   albuminfo = LIBMTP_new_album_t();
    296 
    297   if (palbum) {
    298     printf("Album:     %s\n", palbum);
    299     trackmeta->album = strdup(palbum);
    300     albuminfo->name = strdup(palbum);
    301   }
    302   if (palbumartist) {
    303     printf("Album artist:    %s\n", palbumartist);
    304     albuminfo->artist = strdup(palbumartist);
    305   }
    306   if (partist) {
    307     printf("Artist:    %s\n", partist);
    308     trackmeta->artist = strdup(partist);
    309     if (palbumartist == NULL)
    310       albuminfo->artist = strdup(partist);
    311   }
    312   if (pcomposer) {
    313     printf("Writer or Composer:    %s\n", pcomposer);
    314     trackmeta->composer = strdup(pcomposer);
    315     albuminfo->composer = strdup(pcomposer);
    316   }
    317   if (pgenre) {
    318     printf("Genre:     %s\n", pgenre);
    319     trackmeta->genre = strdup(pgenre);
    320     albuminfo->genre = strdup(pgenre);
    321   }
    322   if (year > 0) {
    323     char tmp[80];
    324     printf("Year:      %d\n", year);
    325     snprintf(tmp, sizeof(tmp)-1, "%4d0101T0000.0", year);
    326     tmp[sizeof(tmp)-1] = '\0';
    327     trackmeta->date = strdup(tmp);
    328   }
    329   if (tracknum > 0) {
    330     printf("Track no:  %d\n", tracknum);
    331     trackmeta->tracknumber = tracknum;
    332   }
    333   if (length > 0) {
    334     printf("Length:    %d\n", length);
    335     // Multiply by 1000 since this is in milliseconds
    336     trackmeta->duration = length * 1000;
    337   }
    338   // We should always have this
    339   if (filename != NULL) {
    340     trackmeta->filename = strdup(filename);
    341   }
    342   trackmeta->filesize = filesize;
    343   trackmeta->parent_id = parent_id;
    344   {
    345     int rc;
    346     char *desc = NULL;
    347     LIBMTP_devicestorage_t *pds = NULL;
    348 
    349     if (0 != (rc=LIBMTP_Get_Storage(device, LIBMTP_STORAGE_SORTBY_NOTSORTED))) {
    350       perror("LIBMTP_Get_Storage()");
    351       exit(-1);
    352     }
    353     for (pds = device->storage; pds != NULL; pds = pds->next) {
    354       if (pds->id == storageid) {
    355 	desc = strdup(pds->StorageDescription);
    356 	break;
    357       }
    358     }
    359     if (NULL != desc) {
    360       printf("Storage ID: %s (%u)\n", desc, storageid);
    361       free(desc);
    362     } else
    363       printf("Storage ID: %u\n", storageid);
    364     trackmeta->storage_id = storageid;
    365   }
    366 
    367   printf("Sending track...\n");
    368   ret = LIBMTP_Send_Track_From_File(device, from_path, trackmeta, progress, NULL);
    369   printf("\n");
    370   if (ret != 0) {
    371     printf("Error sending track.\n");
    372     LIBMTP_Dump_Errorstack(device);
    373     LIBMTP_Clear_Errorstack(device);
    374     ret = 1;
    375   } else {
    376     printf("New track ID: %d\n", trackmeta->item_id);
    377   }
    378 
    379   /* Add here add to album call */
    380   if (palbum)
    381     ret = add_track_to_album(albuminfo, trackmeta);
    382 
    383   LIBMTP_destroy_album_t(albuminfo);
    384   LIBMTP_destroy_track_t(trackmeta);
    385   free (to_path_copy);
    386 
    387   return ret;
    388 }
    389 
    390 int sendtrack_command (int argc, char **argv) {
    391   int opt, ret;
    392   extern int optind;
    393   extern char *optarg;
    394   char *partist = NULL;
    395   char *palbumartist = NULL;
    396   char *pcomposer = NULL;
    397   char *ptitle = NULL;
    398   char *pgenre = NULL;
    399   char *pcodec = NULL;
    400   char *palbum = NULL;
    401   uint16_t tracknum = 0;
    402   uint16_t length = 0;
    403   uint16_t year = 0;
    404   uint16_t quiet = 0;
    405   uint32_t storageid = 0;
    406   while ( (opt = getopt(argc, argv, "qD:t:a:A:w:l:c:g:n:d:y:s:")) != -1 ) {
    407     switch (opt) {
    408     case 't':
    409       free (ptitle);
    410       ptitle = strdup(optarg);
    411       break;
    412     case 'a':
    413       free (partist);
    414       partist = strdup(optarg);
    415       break;
    416     case 'A':
    417       free (palbumartist);
    418       palbumartist = strdup(optarg);
    419       break;
    420     case 'w':
    421       free (pcomposer);
    422       pcomposer = strdup(optarg);
    423       break;
    424     case 'l':
    425       free (palbum);
    426       palbum = strdup(optarg);
    427       break;
    428     case 'c':
    429       free (pcodec);
    430       pcodec = strdup(optarg); // FIXME: DSM check for MP3, WAV or WMA
    431       break;
    432     case 'g':
    433       free (pgenre);
    434       pgenre = strdup(optarg);
    435       break;
    436     case 'n':
    437       tracknum = atoi(optarg);
    438       break;
    439     case 's':
    440       storageid = (uint32_t) strtoul(optarg, NULL, 0);
    441       break;
    442     case 'd':
    443       length = atoi(optarg);
    444       break;
    445     case 'y':
    446       year = atoi(optarg);
    447       break;
    448     case 'q':
    449       quiet = 1;
    450       break;
    451     default:
    452       sendtrack_usage();
    453     }
    454   }
    455   argc -= optind;
    456   argv += optind;
    457 
    458   if ( argc != 2 ) {
    459     printf("You need to pass a filename and destination.\n");
    460     sendtrack_usage();
    461     ret = 0;
    462   } else {
    463     checklang();
    464     printf("%s,%s,%s,%s,%s,%s,%s,%s,%d%d,%d,%u,%d\n",argv[0],argv[1],partist,palbumartist,ptitle,pgenre,palbum,pcomposer,tracknum, length, year, storageid, quiet);
    465     ret = sendtrack_function(argv[0],argv[1],partist,palbumartist,ptitle,pgenre,palbum,pcomposer, tracknum, length, year, storageid, quiet);
    466   }
    467   free (ptitle);
    468   free (partist);
    469   free (palbumartist);
    470   free (pcomposer);
    471   free (palbum);
    472   free (pcodec);
    473   free (pgenre);
    474   return ret;
    475 }
    476