/* * @(#)Client.cpp * * This file is part of webCDwriter - Network CD/DVD Writing. * * Copyright (C) 2000-2005 Jörg P. M. Haeger * * webCDwriter is free software. See rcdrecord.cpp for details. */ #include #include #include #include #include #include #include #include #include "Client.h" #include "CommandArgs.h" #include "Error.h" #include "Hints.h" Client::Client() { verbose = 0; totalKB = oldFreeKB = newFreeKB = 0; CDwasClosed = anonymousUse = copySupport = mp3 = verify = 0; medium = "CD-R(W)"; activeLineLength = 0; writer = -1; } void Client::burnSession(CommandArgs &args, int blankTOC) { if (blankTOC) { fprintf(outStream, "setBlankTOC\n"); readResult(); } if (!args.multi) { fprintf(outStream, "setCloseCD\n"); readResult(); } if (args.copies > 1) { fprintf(outStream, "setCopies %d\n", args.copies); readResult(); } medium = args.medium; exec("setMedium", medium); if (args.dummy) { fprintf(outStream, "setLaserOff\n"); readResult(); } if (args.speed >= 1) { fprintf(outStream, "setSpeed %d\n", args.speed); readResult(); } if (args.uid[0] != 0) exec("setAcceptKey", args.uid); if (args.verify) { fprintf(outStream, "setVerify\n"); readResult(); } println("Trying to reserve the %s-writer...", medium); fprintf(outStream, "burnSession\n"); readResult(); println("%d MB were successfully written.", (oldFreeKB - newFreeKB) / 1024); if (CDwasClosed) println("The %s was closed. It's not possible to add " "further sessions.", medium); else println("Now there are %d of %d MB left.", newFreeKB / 1024, totalKB / 1024); } void Client::blank(const char *mode) { println("Trying to reserve the %s-writer...", medium); fprintf(outStream, "blank %s\n", mode); readResult(); println("The %s was successfully erased.", medium); } void Client::client(const char *product, const char *version) { exec("client", product, version); } void Client::connect(const char *host, int port) { struct hostent *hostinfo; hostinfo = gethostbyname(host); if (hostinfo == NULL) throw new Error("Cannot resolve hostname \"%s\".", host); socket = ::socket(PF_INET, SOCK_STREAM, 0); if (socket < 0) throw "Cannot get a socket."; struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = *(struct in_addr *)hostinfo->h_addr; int res = ::connect(socket, (struct sockaddr *)&addr, sizeof addr); if (res != 0) throw new Error("Cannot connect to \"%s:%d\".\n" "\tUse the dev option to set the CDWserver " "host (and port).", host, port); inStream = fdopen(socket, "r"); assert(inStream != NULL); outStream = fdopen(socket, "w"); assert(outStream != NULL); exec("CDWP"); char *strs[10]; int count = 0; if (mp3) strs[count++] = "mp3 decoding for audio CDs"; if (verify) strs[count++] = "verifying CDs"; if (count > 0) print("CDWserver supports "); for (int i = 0; i < count; i++) if (i + 2 < count) printf("%s, ", strs[i]); else if (i + 1 < count) printf("%s, and ", strs[i]); else printf("%s", strs[i]); if (count > 0) printlnContinued("."); } void Client::exec(const char *command, const char *arg1, const char *arg2, const char *arg3) { fprintf(outStream, "%s", command); if (arg1[0] != 0) { const char *str = spaceToEsc(arg1); fprintf(outStream, " %s", str); delete[] str; } if (arg2[0] != 0) { const char *str = spaceToEsc(arg2); fprintf(outStream, " %s", str); delete[] str; } if (arg3[0] != 0) { const char *str = spaceToEsc(arg3); fprintf(outStream, " %s", str); delete[] str; } fprintf(outStream, "\n"); readResult(); } void Client::listSessions() { exec("listSessions"); } void Client::login(const char *id, const char *password) { exec("login", id, password); } void Client::mkdir(wchar_t *name, int mode, int lastModified) { char *name2 = spaceToEsc(name); fprintf(outStream, "mkdir %s %o %d\n", name2, mode, lastModified); delete[] name2; readResult(); } void Client::newAccount(const char *userID, const char *eMail) { exec("newAccount", userID, eMail); } void Client::newSession(const char *id) { exec("newSession", id); } void Client::noop() { fprintf(outStream, "noop\n"); readResult(); } void Client::openSession(const char *id) { exec("openSession", id); } void Client::print(const char *format, ...) { char line[4 * 1024]; va_list ap; va_start(ap, format); vsnprintf(line, sizeof line, format, ap); va_end(ap); if (activeLineLength > 0) printf("\n"); activeLineLength = 0; if (writer >= 0) { printf("Writer %d: ", writer); activeLineLength += 10; } printf("%s", line); fflush(stdout); activeLineLength += strlen(line); } void Client::printRestarted(const char *format, ...) { char line[4 * 1024]; va_list ap; va_start(ap, format); vsnprintf(line, sizeof line, format, ap); va_end(ap); if (activeLineLength > 0) printf("\r"); int oldLength = activeLineLength; activeLineLength = 0; if (writer >= 0) { printf("Writer %d: ", writer); activeLineLength += 10; } printf("%s", line); activeLineLength += strlen(line); while (oldLength-- > activeLineLength) printf(" "); fflush(stdout); } void Client::println(const char *format, ...) { char line[4 * 1024]; va_list ap; va_start(ap, format); vsnprintf(line, sizeof line, format, ap); va_end(ap); if (activeLineLength > 0) printf("\n"); if (writer >= 0) printf("Writer %d: ", writer); printf("%s\n", line); activeLineLength = 0; } void Client::printlnContinued(const char *format, ...) { char line[4 * 1024]; va_list ap; va_start(ap, format); vsnprintf(line, sizeof line, format, ap); va_end(ap); if (activeLineLength == 0 && writer >= 0) printf("Writer %d: ", writer); printf("%s\n", line); activeLineLength = 0; } void Client::printlnRestarted(const char *format, ...) { char line[4 * 1024]; va_list ap; va_start(ap, format); vsnprintf(line, sizeof line, format, ap); va_end(ap); if (activeLineLength > 0) printf("\r"); if (writer >= 0) printf("Writer %d: ", writer); printf("%s\n", line); activeLineLength = 0; } void Client::putFile(wchar_t *name, int length, int mode, int lastModified, FILE *inStream) { char *name2 = spaceToEsc(name); fprintf(outStream, "putFile %s %d %o %d\n", name2, length, mode, lastModified); delete[] name2; int bytesTransmitted = 0; while (bytesTransmitted < length) { char buf[32 * 1024]; int step = sizeof buf; if (step > length - bytesTransmitted) step = length - bytesTransmitted; int n = fread(buf, 1, step, inStream); if (n < step) break; int m = fwrite(buf, 1, n, outStream); if (m < n) throw "Cannot transmit block."; bytesTransmitted += n; if (length > 0) { printf("\b\b\b\b\b\b\b%6.2f%%", 100.0 * bytesTransmitted / length); fflush(stdout); } } readResult(); } void Client::putTrack(const char *type, int length, const void *bytes) { fprintf(outStream, "putTrack %s %d\n", type, length); int n = fwrite(bytes, 1, length, outStream); if (n < length) throw "Cannot transmit block."; readResult(); } void Client::quit() { fprintf(outStream, "quit\n"); readResult(); } void Client::readResult() { fflush(outStream); while (1) { char line[1024]; if (fgets(line, sizeof line, inStream) == NULL) throw new Error("Unexpected end of inStream"); char *nl = strchr(line, '\n'); if (nl != NULL) *nl = 0; writer = -1; char *type = line; while (*type == ' ') type++; if (sscanf(type, "W%d", &writer) == 1) { while (*type != ' ') type++; } while (*type == ' ') type++; char *msg = type; while (*msg != ' ') msg++; *msg = 0; msg++; while (*msg == ' ') msg++; if (strcmp(type, "CDRECORD") == 0) { int no, a, b; if (strstr(msg, "Last chance to quit") == msg) { if (strchr(msg, '1') != NULL) printlnRestarted(msg); else printRestarted(msg); } else if (sscanf(msg, "Track %d: %d of %d", &no, &a, &b) == 3) { if (a == b) printlnRestarted(msg); else printRestarted(msg); } else if (msg[0] == 0) ; else if (verbose || strstr(msg, "Cdrecord ") == msg || strstr(msg, "Blocks ") == msg || strstr(msg, "Starting ") == msg || strstr(msg, "Fixating...") == msg) println(msg); } else if (strcmp(type, "CDWverify") == 0) { int n; if (strstr(msg, "files are identical") != NULL) println(msg); else if (sscanf(msg, "%d", &n) == 1) printRestarted(msg); else if (verbose || strstr(msg, "CDWverify ") == msg) println(msg); } else if (strcmp(type, "ERR") == 0) { print(""); throw new Error("%s", msg); } else if (strcmp(type, "HINT") == 0) { int a, b, c, n; if (strcmp(msg, "anonymousUse") == 0) anonymousUse = 1; else if (sscanf(msg, "capacity %d %d %d", &a, &b, &c) == 3) { totalKB = a; oldFreeKB = b; newFreeKB = c; } else if (strcmp(msg, "copySupport") == 0) copySupport = 1; else if (sscanf(msg, "defaultSpeed %d", &n) == 1) ; else if (sscanf(msg, "files %d", &n) == 1) ; else if (sscanf(msg, "maxSpeed %d", &n) == 1) ; else if (strcmp(msg, "mp3") == 0) mp3 = 1; else if (sscanf(msg, "msinfo %d %d", &a, &b) == 2) ; else if (strncmp(msg, "Track", 5) == 0) ; else if (sscanf(msg, "tracks %d", &n) == 1) ; else if (sscanf(msg, "rank %d", &n) == 1) printf("No %d in the waiting queue\n", n); else if (strcmp(msg, "verify") == 0) verify = 1; else if (strcmp(msg, hintBlankingTOC) == 0) print("Blanking the TOC..."); else if (strcmp(msg, hintCDdetected) == 0) printlnContinued(" medium detected"); else if (strcmp(msg, hintCDrecordStarted) == 0) println("cdrecord started ==>"); else if (strcmp(msg, hintCDwasClosed) == 0) CDwasClosed = 1; else if (strcmp(msg, hintFixating) == 0) ; else if (strcmp(msg, "growisofs started") == 0) println("growisofs started ==>"); else if (strcmp(msg, hintImageReady) == 0) ; else if (strcmp(msg, hintMakingImage) == 0) println("mkisofs started ==>"); else if (strstr(msg, hintPercentDone) == msg) ; else if (strcmp(msg, hintVerifying) == 0) println("CDWverify started ==>"); else if (strcmp(msg, hintWriterReserved) == 0) print("Waiting for a %s...\007", medium); else if (debug) println("debug: %s", msg); } else if (strcmp(type, "INFO") == 0) { // remove HTML tags char *ptr = msg; while (*ptr != 0) { if (*ptr == '<') { char *ptr2 = ptr; while (*ptr2 != 0 && *ptr2 != '>') ptr2++; if (*ptr2 != 0) ptr2++; char *ptr3 = ptr; while (*ptr2 != 0) *ptr3++ = *ptr2++; *ptr3 = 0; } ptr++; } println("* %s", msg); } else if (strcmp(type, "MKISOFS") == 0) { if (strstr(msg, "estimate finish") != NULL || strstr(msg, ", remaining ") != NULL) printRestarted("%s", msg); else if (verbose || strstr(msg, "mkisofs") == msg || strstr(msg, "extents") != NULL) println("%s", msg); } else if (strcmp(type, "OK") == 0) break; else { int code; if (sscanf(type, "%d", &code) == 1) { if (code == 101 || code >= 900) println("%s", msg); } else if (debug) println("debug: <%s> <%s>", type, msg); } } } void Client::setDebug() { debug = 1; } void Client::setFilesystem(int joliet, int rockRidge, int HFS) { if (joliet) { fprintf(outStream, "setJoliet\n"); readResult(); } if (HFS) { fprintf(outStream, "setHFS\n"); readResult(); } if (rockRidge) { fprintf(outStream, "setRockRidge\n"); readResult(); } } void Client::setProtocol(int version) { fprintf(outStream, "setProtocol %d\n", version); readResult(); } void Client::setVerbose() { verbose = 1; } /** * replace 0x00 to 0x20 by %00 to %20 */ char *Client::spaceToEsc(const char *str) { wchar_t *str2 = new wchar_t[strlen(str) + 1]; assert(mbstowcs(str2, str, strlen(str) + 1) != -1); char *str3 = spaceToEsc(str2); delete[] str2; return str3; } /** * replace 0x00 to 0x20 by %00 to %20 */ char *Client::spaceToEsc(wchar_t *str) { int len = wcslen(str); char *str2 = new char[6 * len + 1]; int i, j; for (i = 0, j = 0; i < len; i++) { wchar_t code = str[i]; if (code > 0x20 && code < 0x7F && code != '%') str2[j++] = code; else if (code < 0x100) { str2[j++] = '%'; sprintf(&str2[j], "%02x", code); j += 2; } else { str2[j++] = '%'; str2[j++] = 'u'; sprintf(&str2[j], "%04x", code); j += 4; } } str2[j] = 0; return str2; } void Client::system(const char *name, const char *version) { exec("system", name, version); } void Client::user(int id, const char *name) { fprintf(outStream, "user %d %s\n", id, name); readResult(); }