int netmd_delete_group(usb_dev_handle* dev, minidisc* md, int group) { int index = 0; struct netmd_group *p; /* check if requested group exists */ if((group < 0) || (group > md->group_count)) return -1; /* create a copy of groups below requested group */ p = malloc(sizeof(struct netmd_group) * md->group_count); for(index = 0; index < group; index++) { p[index].name = strdup(md->groups[index].name); p[index].start = md->groups[index].start; p[index].finish = md->groups[index].finish; } /* copy groups above requested group */ for(; index < md->group_count-1; index++) { p[index].name = strdup(md->groups[index+1].name); p[index].start = md->groups[index+1].start; p[index].finish = md->groups[index+1].finish; } /* free all memory, then make our copy the real info */ netmd_clean_disc_info(md); md->groups = p; /* one less group now */ md->group_count--; netmd_write_disc_header(dev, md); return 0; }
int main(int argc, char* argv[]) { netmd_dev_handle* devh; minidisc my_minidisc, *md = &my_minidisc; netmd_device *device_list, *netmd; unsigned int i = 0; unsigned int j = 0; char name[16]; uint16_t track, playmode; int c; netmd_time time; netmd_error error; FILE *f; error = netmd_init(&device_list); if (error != NETMD_NO_ERROR) { printf("Error initializing netmd\n%s\n", netmd_strerror(error)); return -1; } if (device_list == NULL) { puts("Found no NetMD device(s)."); return -1; } /* pick first available device */ netmd = device_list; error = netmd_open(netmd, &devh); if(error != NETMD_NO_ERROR) { printf("Error opening netmd\n%s\n", netmd_strerror(error)); return -1; } error = netmd_get_devname(devh, name, 16); if (error != NETMD_NO_ERROR) { printf("Could not get device name\n%s\n", netmd_strerror(error)); return -1; } printf("%s\n", name); netmd_initialize_disc_info(devh, md); printf("Disc Title: %s\n\n", md->groups[0].name); /* by default, log only errors */ netmd_set_log_level(NETMD_LOG_ERROR); /* parse options */ while (1) { c = getopt(argc, argv, "t"); if (c == -1) { break; } switch (c) { case 't': netmd_set_log_level(NETMD_LOG_ALL); break; default: fprintf(stderr, "Unknown option '%c'\n", c); break; } } /* update argv and argc after parsing options */ argv = &argv[optind - 1]; argc -= (optind - 1); /* parse commands */ if(argc > 1) { if(strcmp("rename", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); netmd_cache_toc(devh); netmd_set_title(devh, i & 0xffff, argv[3]); netmd_sync_toc(devh); } else if(strcmp("move", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); j = strtoul(argv[3], NULL, 10); netmd_move_track(devh, i & 0xffff, j & 0xffff); } else if(strcmp("groupmove", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); j = strtoul(argv[3], NULL, 10); netmd_move_group(devh, md, j & 0xffff, i & 0xffff); } else if(strcmp("write", argv[1]) == 0) { if(netmd_write_track(devh, argv[2]) < 0) { fprintf(stderr, "Error writing track %i\n", errno); } } else if(strcmp("newgroup", argv[1]) == 0) { netmd_create_group(devh, md, argv[2]); } else if(strcmp("settitle", argv[1]) == 0) { netmd_cache_toc(devh); netmd_set_disc_title(devh, argv[2], strlen(argv[2])); netmd_sync_toc(devh); } else if(strcmp("group", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); j = strtoul(argv[3], NULL, 10); if(!netmd_put_track_in_group(devh, md, i & 0xffff, j & 0xffff)) { printf("Something screwy happened\n"); } } else if(strcmp("retitle", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); netmd_set_group_title(devh, md, i, argv[3]); } else if(strcmp("play", argv[1]) == 0) { if( argc > 2 ) { i = strtoul(argv[2],NULL, 10); netmd_set_track( devh, i & 0xffff ); } netmd_play(devh); } else if(strcmp("stop", argv[1]) == 0) { netmd_stop(devh); } else if(strcmp("pause", argv[1]) == 0) { netmd_pause(devh); } else if(strcmp("fforward", argv[1]) == 0) { netmd_fast_forward(devh); } else if(strcmp("rewind", argv[1]) == 0) { netmd_rewind(devh); } else if(strcmp("next", argv[1]) == 0) { netmd_track_next(devh); } else if(strcmp("previous", argv[1]) == 0) { netmd_track_previous(devh); } else if(strcmp("restart", argv[1]) == 0) { netmd_track_restart(devh); } else if(strcmp("settime", argv[1]) == 0) { track = strtoul(argv[2], (char **) NULL, 10) & 0xffff; if (argc > 6) { time.hour = strtoul(argv[3], (char **) NULL, 10) & 0xffff; time.minute = strtoul(argv[4], (char **) NULL, 10) & 0xff; time.second = strtoul(argv[5], (char **) NULL, 10) & 0xff; time.frame = strtoul(argv[6], (char **) NULL, 10) & 0xff; } else { time.hour = 0; time.minute = strtoul(argv[3], (char **) NULL, 10) & 0xff; time.second = strtoul(argv[4], (char **) NULL, 10) & 0xff; if (argc > 5) { time.frame = strtoul(argv[5], (char **) NULL, 10) & 0xff;; } else { time.frame = 0; } } netmd_set_time(devh, track, &time); } else if(strcmp("m3uimport", argv[1]) == 0) { import_m3u_playlist(devh, argv[2]); } else if(strcmp("delete", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); netmd_delete_track(devh, i & 0xffff); } else if(strcmp("deletegroup", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); netmd_delete_group(devh, md, i & 0xffff); } else if(strcmp("status", argv[1]) == 0) { print_current_track_info(devh); } else if (strcmp("raw", argv[1]) == 0) { send_raw_message(devh, argv[2]); } else if (strcmp("setplaymode", argv[1]) == 0) { playmode = 0; int i; for (i = 2; i < argc; i++) { if (strcmp(argv[i], "single") == 0) { playmode |= NETMD_PLAYMODE_SINGLE; } else if (strcmp(argv[i], "repeat") == 0) { playmode |= NETMD_PLAYMODE_REPEAT; } else if (strcmp(argv[i], "shuffle") == 0) { playmode |= NETMD_PLAYMODE_SHUFFLE; } } printf("%x\n", playmode); netmd_set_playmode(devh, playmode); } else if (strcmp("capacity", argv[1]) == 0) { netmd_disc_capacity capacity; netmd_get_disc_capacity(devh, &capacity); printf("Recorded: "); print_time(&capacity.recorded); printf("\nTotal: "); print_time(&capacity.total); printf("\nAvailable: "); print_time(&capacity.available); printf("\n"); } else if (strcmp("recv", argv[1]) == 0) { i = strtoul(argv[2], NULL, 10); f = fopen(argv[3], "wb"); netmd_secure_recv_track(devh, i & 0xffff, f); fclose(f); } else if (strcmp("send", argv[1]) == 0) { netmd_error error; netmd_ekb ekb; unsigned char chain[] = {0x25, 0x45, 0x06, 0x4d, 0xea, 0xca, 0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4, 0x06, 0xc2, 0x2b, 0x81, 0x49, 0xba, 0xf0, 0xdf, 0x26, 0x9d, 0xb7, 0x1d, 0x49, 0xba, 0xf0, 0xdf, 0x26, 0x9d, 0xb7, 0x1d}; unsigned char signature[] = {0xe8, 0xef, 0x73, 0x45, 0x8d, 0x5b, 0x8b, 0xf8, 0xe8, 0xef, 0x73, 0x45, 0x8d, 0x5b, 0x8b, 0xf8, 0x38, 0x5b, 0x49, 0x36, 0x7b, 0x42, 0x0c, 0x58}; unsigned char rootkey[] = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37, 0x13, 0x37, 0x13, 0x37, 0x13, 0x37, 0x13, 0x37, 0x13, 0x37}; netmd_keychain *keychain; netmd_keychain *next; size_t done; unsigned char hostnonce[8] = { 0 }; unsigned char devnonce[8] = { 0 }; unsigned char sessionkey[8] = { 0 }; unsigned char kek[] = { 0x14, 0xe3, 0x83, 0x4e, 0xe2, 0xd3, 0xcc, 0xa5 }; unsigned char contentid[] = { 0x01, 0x0F, 0x50, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, 0xA2, 0x8D, 0x3E, 0x1A, 0x3B, 0x0C, 0x44, 0xAF, 0x2f, 0xa0 }; netmd_track_packets *packets = NULL; size_t packet_count = 0; struct stat stat_buf; unsigned char *data; size_t data_size; uint16_t track; unsigned char uuid[8] = { 0 }; unsigned char new_contentid[20] = { 0 }; error = netmd_secure_leave_session(devh); puts(netmd_strerror(error)); error = netmd_secure_set_track_protection(devh, 0x01); puts(netmd_strerror(error)); error = netmd_secure_enter_session(devh); puts(netmd_strerror(error)); /* build ekb */ ekb.id = 0x26422642; ekb.depth = 9; ekb.signature = malloc(sizeof(signature)); memcpy(ekb.signature, signature, sizeof(signature)); /* build ekb key chain */ ekb.chain = NULL; for (done = 0; done < sizeof(chain); done+=16U) { next = malloc(sizeof(netmd_keychain)); if (ekb.chain == NULL) { ekb.chain = next; } else { keychain->next = next; } next->next = NULL; next->key = malloc(16); memcpy(next->key, chain + done, 16); keychain = next; } error = netmd_secure_send_key_data(devh, &ekb); puts(netmd_strerror(error)); /* cleanup */ free(ekb.signature); keychain = ekb.chain; while (keychain != NULL) { next = keychain->next; free(keychain->key); free(keychain); keychain = next; } /* exchange nonces */ gcry_create_nonce(hostnonce, sizeof(hostnonce)); error = netmd_secure_session_key_exchange(devh, hostnonce, devnonce); puts(netmd_strerror(error)); /* calculate session key */ retailmac(rootkey, hostnonce, devnonce, sessionkey); error = netmd_secure_setup_download(devh, contentid, kek, sessionkey); puts(netmd_strerror(error)); /* read source */ stat(argv[2], &stat_buf); data_size = (size_t)stat_buf.st_size; data = malloc(data_size); f = fopen(argv[2], "rb"); fseek(f, 60, SEEK_CUR); fread(data, data_size - 60, 1, f); fclose(f); error = netmd_prepare_packets(data, data_size-60, &packets, &packet_count, kek); puts(netmd_strerror(error)); /* send to device */ error = netmd_secure_send_track(devh, NETMD_WIREFORMAT_LP2, NETMD_DISKFORMAT_LP2, (data_size - 60) / 192, packets, packet_count, sessionkey, &track, uuid, new_contentid); puts(netmd_strerror(error)); /* cleanup */ netmd_cleanup_packets(&packets); /* set title */ netmd_log(NETMD_LOG_DEBUG, "New Track: %d\n", track); netmd_cache_toc(devh); netmd_set_title(devh, track, "test"); netmd_sync_toc(devh); /* commit track */ error = netmd_secure_commit_track(devh, track, sessionkey); puts(netmd_strerror(error)); /* forget key */ error = netmd_secure_session_key_forget(devh); puts(netmd_strerror(error)); /* leave session */ error = netmd_secure_leave_session(devh); puts(netmd_strerror(error)); } else if(strcmp("help", argv[1]) == 0) { print_syntax(); } else { print_disc_info(devh, md); print_syntax(); } } else print_disc_info(devh, md); netmd_clean_disc_info(md); netmd_close(devh); netmd_clean(&device_list); return 0; }
int netmd_move_group(usb_dev_handle* dev, minidisc* md, int track, int group) { int index = 0; int i = 0; int gs = 0; struct netmd_group store1; struct netmd_group *p, *p2; int gt = md->groups[group].start; int finish = (md->groups[group].finish - md->groups[group].start) + track; p = p2 = 0; // empty groups can't be in front if(gt == 0) return -1; /* loop, moving tracks to new positions */ for(index = track; index <= finish; index++, gt++) { printf("Moving track %i to %i\n", (gt - 1), index); netmd_move_track(dev, (gt -1), index); } md->groups[group].start = track + 1; md->groups[group].finish = index; /* create a copy of groups */ p = malloc(sizeof(struct netmd_group) * md->group_count); for(index = 0; index < md->group_count; index++) { p[index].name = malloc(strlen(md->groups[index].name) + 1); strcpy(p[index].name, md->groups[index].name); p[index].start = md->groups[index].start; p[index].finish = md->groups[index].finish; } store1 = p[group]; gs = store1.finish - store1.start + 1; /* how many tracks got moved? */ /* find group to bump */ if(track < md->groups[group].start) { for(index = 0; index < md->group_count; index++) { if(md->groups[index].start > track) { for(i = group - 1; i >= index; i--) { /* all tracks get moved gs spots */ p[i].start += gs; if(p[i].finish != 0) p[i].finish += gs; p[i + 1] = p[i]; /* bump group down the list */ } p[index] = store1; break; } else { if((group + 1) < md->group_count) { for(i = group + 1; i < md->group_count; i++) { /* all tracks get moved gs spots */ p[i].start -= gs; if(p[i].finish != 0) p[i].finish -= gs; p[i - 1] = p[i]; /* bump group down the list */ } p[index] = store1; break; } } } } /* free all memory, then make our copy the real info */ netmd_clean_disc_info(md); md->groups = p; netmd_write_disc_header(dev, md); return 0; }