1 /* 2 * Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <getopt.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <Application.h> 13 #include <Mime.h> 14 #include <Path.h> 15 16 #include <mime/AppMetaMimeCreator.h> 17 #include <mime/Database.h> 18 #include <mime/DatabaseLocation.h> 19 #include <mime/MimeInfoUpdater.h> 20 21 22 using namespace BPrivate::Storage::Mime; 23 24 25 #ifdef HAIKU_HOST_PLATFORM_SUNOS 26 static const char* sProgramName = "mimeset"; 27 #else 28 extern const char* __progname; 29 static const char* sProgramName = __progname; 30 #endif 31 32 // options 33 bool gFiles = true; 34 bool gApps = false; 35 int gForce = B_UPDATE_MIME_INFO_NO_FORCE; 36 37 static Database* sDatabase = NULL; 38 39 40 static void 41 usage(int status) 42 { 43 printf("Usage: %s <options> <path> ...\n" 44 "Recursively updates the MIME related attributes (e.g. file type) for\n" 45 "the given files. Alternatively or additionally encountered\n" 46 "applications are entered into the MIME database. When \"@\" is\n" 47 "specified as <path>, file paths are read from stdin.\n" 48 "\n" 49 "Options:\n" 50 " -A, --all\n" 51 " Update the files' MIME information and enter applications into\n" 52 " the MIME database.\n" 53 " -a, --apps\n" 54 " Only enter applications into the MIME database.\n" 55 " -f\n" 56 " Force updating, even if previously updated, but do not overwrite\n" 57 " the type of a file.\n" 58 " -F\n" 59 " Force updating, even if previously updated. Also overwrite the\n" 60 " type of a file.\n" 61 " -h, --help\n" 62 " Display this help information.\n" 63 " -m, --mimedb <directory>\n" 64 " Instead of the system MIME DB use the given directory\n" 65 " <directory>. The option can occur multiple times to specify a\n" 66 " list of directories. MIME DB changes are written to the first\n" 67 " specified directory.\n" 68 "\n" 69 "Obsolete options:\n" 70 " -all (synonymous with --all)\n" 71 " -apps (synonymous with --apps)\n" 72 "\n", 73 sProgramName); 74 75 exit(status); 76 } 77 78 79 static status_t 80 process_file_with_custom_mime_db(const BEntry& entry) 81 { 82 AppMetaMimeCreator appMetaMimeCreator(sDatabase, NULL, gForce); 83 MimeInfoUpdater mimeInfoUpdater(sDatabase, NULL, gForce); 84 85 entry_ref ref; 86 status_t error = entry.GetRef(&ref); 87 88 if (gFiles && error == B_OK) 89 error = mimeInfoUpdater.DoRecursively(ref); 90 if (gApps && error == B_OK) { 91 error = appMetaMimeCreator.DoRecursively(ref); 92 if (error == B_BAD_TYPE) { 93 // Ignore B_BAD_TYPE silently. The most likely cause is that the 94 // file doesn't have a "BEOS:APP_SIG" attribute. 95 error = B_OK; 96 } 97 } 98 99 if (error != B_OK) { 100 BPath path; 101 fprintf(stderr, "%s: \"%s\": %s\n", 102 sProgramName, 103 entry.GetPath(&path) == B_OK ? path.Path() : entry.Name(), 104 strerror(error)); 105 return error; 106 } 107 108 return B_OK; 109 } 110 111 112 static status_t 113 process_file(const char* path) 114 { 115 status_t status = B_OK; 116 117 BEntry entry(path); 118 if (!entry.Exists()) 119 status = B_ENTRY_NOT_FOUND; 120 121 if (sDatabase != NULL) 122 return process_file_with_custom_mime_db(entry); 123 124 if (gFiles && status == B_OK) 125 status = update_mime_info(path, true, true, gForce); 126 if (gApps && status == B_OK) 127 status = create_app_meta_mime(path, true, true, gForce); 128 129 if (status != B_OK) { 130 fprintf(stderr, "%s: \"%s\": %s\n", 131 sProgramName, path, strerror(status)); 132 } 133 return status; 134 } 135 136 137 int 138 main(int argc, const char** argv) 139 { 140 // parse arguments 141 142 // replace old-style options first 143 for (int i = 1; i < argc; i++) { 144 const char* arg = argv[i]; 145 if (*arg != '-') 146 break; 147 if (strcmp(arg, "-all") == 0) 148 argv[i] = "--all"; 149 else if (strcmp(arg, "-apps") == 0) 150 argv[i] = "--apps"; 151 } 152 153 BStringList databaseDirectories; 154 155 for (;;) { 156 static struct option sLongOptions[] = { 157 { "all", no_argument, 0, 'A' }, 158 { "apps", no_argument, 0, 'a' }, 159 { "help", no_argument, 0, 'h' }, 160 { "mimedb", required_argument, 0, 'm' }, 161 { 0, 0, 0, 0 } 162 }; 163 164 opterr = 0; // don't print errors 165 int c = getopt_long(argc, (char**)argv, "aAfFhm:", sLongOptions, 166 NULL); 167 if (c == -1) 168 break; 169 170 switch (c) { 171 case 'a': 172 gApps = true; 173 gFiles = false; 174 break; 175 case 'A': 176 gApps = true; 177 gFiles = true; 178 break; 179 case 'f': 180 gForce = B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE; 181 break; 182 case 'F': 183 gForce = B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL; 184 break; 185 case 'h': 186 usage(0); 187 break; 188 case 'm': 189 databaseDirectories.Add(optarg); 190 break; 191 default: 192 usage(1); 193 break; 194 } 195 } 196 197 if (argc - optind < 1) 198 usage(1); 199 200 // set up custom MIME DB, if specified 201 DatabaseLocation databaseLocation; 202 if (!databaseDirectories.IsEmpty()) { 203 int32 count = databaseDirectories.CountStrings(); 204 for (int32 i = 0; i < count; i++) 205 databaseLocation.AddDirectory(databaseDirectories.StringAt(i)); 206 207 sDatabase = new(std::nothrow) Database(&databaseLocation, NULL, NULL); 208 if (sDatabase == NULL) { 209 fprintf(stderr, "%s: Out of memory!\n", sProgramName); 210 exit(1); 211 } 212 213 status_t error = sDatabase->InitCheck(); 214 if (error != B_OK) { 215 fprintf(stderr, "%s: Failed to init MIME DB: %s\n", sProgramName, 216 strerror(error)); 217 exit(1); 218 } 219 } 220 221 // process files 222 223 BApplication app("application/x-vnd.haiku.mimeset"); 224 225 for (; optind < argc; optind++) { 226 const char* arg = argv[optind]; 227 228 if (strcmp(arg, "@") == 0) { 229 // read file names from stdin 230 char name[B_PATH_NAME_LENGTH]; 231 while (fgets(name, sizeof(name), stdin) != NULL) { 232 name[strlen(name) - 1] = '\0'; 233 // remove trailing '\n' 234 if (process_file(name) != B_OK) 235 exit(1); 236 } 237 } else { 238 if (process_file(arg) != B_OK) 239 exit(1); 240 } 241 } 242 243 return 0; 244 } 245