1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include <AppFileInfo.h> 11 #include <Mime.h> 12 13 static const char *kCommandName = "settype"; 14 15 static int kArgc; 16 static const char *const *kArgv; 17 18 // usage 19 const char *kUsage = 20 "Usage: %s <options> <file> ...\n" 21 "\n" 22 "Sets the MIME type, signature, and/or preferred application of one or more\n" 23 "files.\n" 24 "\n" 25 "Options:\n" 26 " -h, --help\n" 27 " - Print this help text and exit.\n" 28 " -preferredAppSig <signature>\n" 29 " - Set the preferred application of the given files to\n" 30 " <signature>.\n" 31 " -s <signature>\n" 32 " - Set the application signature of the given files to\n" 33 " <signature>.\n" 34 " -t <type>\n" 35 " - Set the MIME type of the given files to <type>.\n" 36 ; 37 38 // print_usage 39 static void 40 print_usage(bool error) 41 { 42 // get command name 43 const char *commandName = NULL; 44 if (kArgc > 0) { 45 if (const char *lastSlash = strchr(kArgv[0], '/')) 46 commandName = lastSlash + 1; 47 else 48 commandName = kArgv[0]; 49 } 50 51 if (!commandName || strlen(commandName) == 0) 52 commandName = kCommandName; 53 54 // print usage 55 fprintf((error ? stderr : stdout), kUsage, commandName, commandName, 56 commandName); 57 } 58 59 // print_usage_and_exit 60 static void 61 print_usage_and_exit(bool error) 62 { 63 print_usage(error); 64 exit(error ? 1 : 0); 65 } 66 67 // next_arg 68 static const char * 69 next_arg(int &argi, bool optional = false) 70 { 71 if (argi >= kArgc) { 72 if (!optional) 73 print_usage_and_exit(true); 74 return NULL; 75 } 76 77 return kArgv[argi++]; 78 } 79 80 // check_mime_type 81 static void 82 check_mime_type(const char *type) 83 { 84 // check type 85 if (type) { 86 if (!BMimeType::IsValid(type)) { 87 fprintf(stderr, "\"%s\" is no valid MIME type.\n", type); 88 89 exit(1); 90 } 91 } 92 } 93 94 // main 95 int 96 main(int argc, const char *const *argv) 97 { 98 kArgc = argc; 99 kArgv = argv; 100 101 // parameters 102 const char **files = new const char*[argc]; 103 int fileCount = 0; 104 const char *type = NULL; 105 const char *signature = NULL; 106 const char *preferredApp = NULL; 107 108 // parse the arguments 109 for (int argi = 1; argi < argc; ) { 110 const char *arg = argv[argi++]; 111 if (arg[0] == '-') { 112 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 113 print_usage_and_exit(false); 114 115 } else if (strcmp(arg, "-preferredAppSig") == 0) { 116 preferredApp = next_arg(argi); 117 118 } else if (strcmp(arg, "-s") == 0) { 119 signature = next_arg(argi); 120 121 } else if (strcmp(arg, "-t") == 0) { 122 type = next_arg(argi); 123 124 } else { 125 fprintf(stderr, "Error: Invalid option: \"%s\"\n", arg); 126 print_usage_and_exit(true); 127 } 128 } else { 129 // file 130 files[fileCount++] = arg; 131 } 132 } 133 134 // check parameters 135 if (!preferredApp && !signature && !type) { 136 fprintf(stderr, "Error: At least one option of \"-preferredAppSig\", " 137 "\"-s\", and \"-t\" must be given.\n"); 138 print_usage_and_exit(true); 139 } 140 141 if (fileCount == 0) { 142 fprintf(stderr, "Error: No file specified.\n"); 143 print_usage_and_exit(true); 144 } 145 146 // check for valid MIME types 147 check_mime_type(preferredApp); 148 check_mime_type(type); 149 check_mime_type(signature); 150 151 // iterate through the files 152 for (int i = 0; i < fileCount; i++) { 153 const char *fileName = files[i]; 154 155 // check, whether the file exists 156 BEntry entry; 157 status_t error = entry.SetTo(fileName, false); 158 if (error != B_OK) { 159 fprintf(stderr, "Error: Can't access file \"%s\": %s\n", 160 fileName, strerror(error)); 161 162 exit(1); 163 } 164 165 if (!entry.Exists()) { 166 fprintf(stderr, "Error: \"%s\": No such file or directory.\n", 167 fileName); 168 169 exit(1); 170 } 171 172 // ... and has the right type 173 if (signature && !entry.IsFile()) { 174 fprintf(stderr, "Error: \"%s\" is not a file. Signatures can only " 175 "be set for executable files.\n", fileName); 176 177 exit(1); 178 } 179 180 // open the file 181 BFile file; 182 BNode _node; 183 BNode &node = (signature ? file : _node); 184 error = (signature ? file.SetTo(fileName, B_READ_WRITE) 185 : node.SetTo(fileName)); 186 if (error != B_OK) { 187 fprintf(stderr, "Error: Failed to open file \"%s\": %s\n", 188 fileName, strerror(error)); 189 190 exit(1); 191 } 192 193 // prepare an node/app info object 194 BAppFileInfo appInfo; 195 BNodeInfo _nodeInfo; 196 BNodeInfo &nodeInfo = (signature ? appInfo : _nodeInfo); 197 error = (signature ? appInfo.SetTo(&file) : nodeInfo.SetTo(&node)); 198 if (error != B_OK) { 199 fprintf(stderr, "Error: Failed to open file \"%s\": %s\n", 200 fileName, strerror(error)); 201 202 exit(1); 203 } 204 205 // set preferred app 206 if (preferredApp) { 207 error = nodeInfo.SetPreferredApp(preferredApp); 208 if (error != B_OK) { 209 fprintf(stderr, "Error: Failed to set the preferred " 210 "application of file \"%s\": %s\n", fileName, 211 strerror(error)); 212 213 exit(1); 214 } 215 } 216 217 // set type 218 if (type) { 219 error = nodeInfo.SetType(type); 220 if (error != B_OK) { 221 fprintf(stderr, "Error: Failed to set the MIME type of file " 222 "\"%s\": %s\n", fileName, strerror(error)); 223 224 exit(1); 225 } 226 } 227 228 // set signature 229 if (signature) { 230 error = appInfo.SetSignature(signature); 231 if (error != B_OK) { 232 fprintf(stderr, "Error: Failed to set the signature of file " 233 "\"%s\": %s\n", fileName, strerror(error)); 234 235 exit(1); 236 } 237 } 238 } 239 240 delete[] files; 241 242 return 0; 243 } 244