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