libmtp: detect.c

# detect.c

    #include "common.h"
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>

    #define XML_BUFSIZE 0x10000

    static void dump_xml_fragment(uint8_t *buf, uint32_t len)
    {
      static int endianness = 0; // 0 = LE, 1 = BE
      uint32_t bp = 0;

      while (bp < len) {
        if (buf[bp+0] == 0xFF && buf[bp+1] == 0xFE) {
          endianness = 0;
        } else if (buf[bp+0] == 0xFE && buf[bp+1] == 0xff) {
          endianness = 1;
        } else {
          uint16_t tmp;

          if (endianness == 0) {
            tmp = buf[bp+1] << 8 | buf[bp+0];
          } else {
            tmp = buf[bp+0] << 8 | buf[bp+1];
          }
          // Fix this some day, we only print ISO 8859-1 correctly here,
          // should atleast support UTF-8.
          printf("%c", (uint8_t) tmp);
        }
        bp += 2;
      }
      printf("\n");
    }

    int main (int argc, char **argv)
    {
      LIBMTP_mtpdevice_t *device, *iter;
      LIBMTP_file_t *files;
      uint32_t xmlfileid = 0;
      char *friendlyname;
      char *syncpartner;
      char *sectime;
      char *devcert;
      uint16_t *filetypes;
      uint16_t filetypes_len;
      uint8_t maxbattlevel;
      uint8_t currbattlevel;
      uint32_t numdevices;
      int ret;
      int probeonly = 0;

      LIBMTP_Init();

      fprintf(stdout, "libmtp version: " LIBMTP_VERSION_STRING "\n\n");
      fprintf(stdout, "Attempting to connect device(s)\n");

      switch(LIBMTP_Get_Connected_Devices(&device))
      {
      case LIBMTP_ERROR_NO_DEVICE_ATTACHED:
        fprintf(stdout, "Detect: No Devices have been found\n");
        return 0;
      case LIBMTP_ERROR_CONNECTING:
        fprintf(stderr, "Detect: There has been an error connecting. Exiting\n");
        return 1;
      case LIBMTP_ERROR_MEMORY_ALLOCATION:
        fprintf(stderr, "Detect: Encountered a Memory Allocation Error. Exiting\n");
        return 1;

      /* Unknown general errors - This should never execute */
      case LIBMTP_ERROR_GENERAL:
      default:
        fprintf(stderr, "Detect: There has been an unknown error, please report "
                        "this to the libmtp developers\n");
      return 1;

      /* Successfully connected at least one device, so continue */
      case LIBMTP_ERROR_NONE:
            numdevices = LIBMTP_Number_Devices_In_List(device);
        fprintf(stdout, "Detect: Successfully connected %u devices\n", numdevices);
      }

      /* iterate through connected MTP devices */
      for(iter = device; iter != NULL; iter = iter->next)
      {

      LIBMTP_Dump_Errorstack(iter);
      LIBMTP_Clear_Errorstack(iter);
      LIBMTP_Dump_Device_Info(iter);

      printf("MTP-specific device properties:\n");
      // The friendly name
      friendlyname = LIBMTP_Get_Friendlyname(iter);
      if (friendlyname == NULL) {
        fprintf(stdout, "   Friendly name: (NULL)\n");
      } else {
        fprintf(stdout, "   Friendly name: %s\n", friendlyname);
        free(friendlyname);
      }
      syncpartner = LIBMTP_Get_Syncpartner(iter);
      if (syncpartner == NULL) {
        fprintf(stdout, "   Synchronization partner: (NULL)\n");
      } else {
       fprintf(stdout, "   Synchronization partner: %s\n", syncpartner);
        free(syncpartner);
      }

      // Some battery info
      ret = LIBMTP_Get_Batterylevel(iter, &maxbattlevel, &currbattlevel);
      if (ret == 0) {
        fprintf(stdout, "   Battery level %d of %d (%d%%)\n",currbattlevel, maxbattlevel,
               (int) ((float) currbattlevel/ (float) maxbattlevel * 100.0));
      } else {
        // Silently ignore. Some devices does not support getting the
        // battery level.
        LIBMTP_Clear_Errorstack(iter);
      }

      ret = LIBMTP_Get_Supported_Filetypes(iter, &filetypes, &filetypes_len);
      if (ret == 0) {
        uint16_t i;

        printf("libmtp supported (playable) filetypes:\n");
        for (i = 0; i < filetypes_len; i++) {
          fprintf(stdout, "   %s\n", LIBMTP_Get_Filetype_Description(filetypes[i]));
        }
      } else {
        LIBMTP_Dump_Errorstack(iter);
        LIBMTP_Clear_Errorstack(iter);
      }

      // Secure time XML fragment
      ret = LIBMTP_Get_Secure_Time(iter, &sectime);
      if (ret == 0 && sectime != NULL) {
        fprintf(stdout, "\nSecure Time:\n%s\n", sectime);
        free(sectime);
      } else {
        // Silently ignore - there may be devices not supporting secure time.
        LIBMTP_Clear_Errorstack(iter);
      }

      // Device certificate XML fragment
      ret = LIBMTP_Get_Device_Certificate(iter, &devcert);
      if (ret == 0 && devcert != NULL) {
        fprintf(stdout, "\nDevice Certificate:\n%s\n", devcert);
        free(devcert);
      } else {
        fprintf(stdout, "Unable to acquire device certificate, perhaps this device "
                        "does not support this\n");
        LIBMTP_Dump_Errorstack(iter);
        LIBMTP_Clear_Errorstack(iter);
      }

      // Try to get Media player device info XML file...
      files = LIBMTP_Get_Filelisting_With_Callback(iter, NULL, NULL);
      if (files != NULL) {
        LIBMTP_file_t *file, *tmp;
        file = files;
        while (file != NULL) {
          if (!strcmp(file->filename, "WMPInfo.xml") ||
                    !strcmp(file->filename, "WMPinfo.xml"))
          {
            xmlfileid = file->item_id;
          }
          tmp = file;
          file = file->next;
          LIBMTP_destroy_file_t(tmp);
        }
      }
      if (xmlfileid == 0)
            fprintf(stdout, "WMPInfo.xml Does not exist on this device\n");
      if (xmlfileid != 0)
      {
        FILE *xmltmp = tmpfile();
        int tmpfiledescriptor = fileno(xmltmp);

        if (tmpfiledescriptor != -1)
        {
          int ret = LIBMTP_Get_Track_To_File_Descriptor(iter,
                                                        xmlfileid,
                                                        tmpfiledescriptor,
                                                        NULL,
                                                        NULL);
          if (ret == 0)
          {
            uint8_t *buf = NULL;
            uint32_t readbytes;

            buf = malloc(XML_BUFSIZE);
            if (buf == NULL)
            {
              printf("Could not allocate %08x bytes...\n", XML_BUFSIZE);
              LIBMTP_Dump_Errorstack(iter);
              LIBMTP_Clear_Errorstack(iter);
              LIBMTP_Release_Device_List(device);
              return 1;
            }

            lseek(tmpfiledescriptor, 0, SEEK_SET);
            readbytes = read(tmpfiledescriptor, (void*) buf, XML_BUFSIZE);

            if (readbytes >= 2 && readbytes < XML_BUFSIZE)
            {
              fprintf(stdout, "\nDevice description WMPInfo.xml file:\n");
              dump_xml_fragment(buf, readbytes);
            }
            else
            {
              perror("Unable to read WMPInfo.xml");
              LIBMTP_Dump_Errorstack(iter);
              LIBMTP_Clear_Errorstack(iter);
            }
            free(buf);
          }
          else
          {
            LIBMTP_Dump_Errorstack(iter);
            LIBMTP_Clear_Errorstack(iter);
          }
          fclose(xmltmp);
        }
      }

      } /* End For Loop */

      LIBMTP_Release_Device_List(device);
      printf("OK.\n");

      return 0;
    }