xref: /haiku/src/bin/settype.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
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