1/*
2 * Copyright 2005, Haiku Inc.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Jonas Sundstr��m, jonas@kirilla.com
7 *		Axel D��rfler, axeld@pinc-software.de.
8 */
9
10
11#include <Application.h>
12#include <Clipboard.h>
13#include <File.h>
14#include <FindDirectory.h>
15#include <Path.h>
16#include <String.h>
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <getopt.h>
22
23
24extern const char *__progname;
25static const char *kProgramName = __progname;
26
27static int sExitValue = EXIT_SUCCESS;
28
29
30class ClipboardApp : public BApplication {
31	public:
32		ClipboardApp(void);
33		virtual ~ClipboardApp(void);
34
35		virtual void ReadyToRun(void);
36		virtual void ArgvReceived(int32 argc, char **argv);
37
38	private:
39		void Usage(void);
40		status_t Load(const char *path);
41		status_t Save(const char *path);
42		status_t Copy(const char *string);
43		status_t Clear(void);
44		status_t Print(bool debug);
45
46		bool fGotArguments;
47};
48
49
50ClipboardApp::ClipboardApp(void)
51	: BApplication("application/x-vnd.haiku-clipboard"),
52	fGotArguments(false)
53{
54}
55
56
57ClipboardApp::~ClipboardApp(void)
58{
59}
60
61
62void
63ClipboardApp::ArgvReceived(int32 argc, char **argv)
64{
65	status_t status = B_OK;
66
67	static struct option const kLongOptions[] = {
68		{"load", required_argument, 0, 'l'},
69		{"save", required_argument, 0, 's'},
70		{"copy", required_argument, 0, 'c'},
71		{"clear", no_argument, 0, 'r'},
72		{"stdin", no_argument, 0, 'i'},
73		{"print", no_argument, 0, 'p'},
74		{"debug", no_argument, 0, 'd'},
75		{"help", no_argument, 0, 'h'},
76		{NULL}
77	};
78
79	int c;
80	while ((c = getopt_long(argc, argv, "l:s:o:c:ripdh", kLongOptions, NULL))
81		!= -1) {
82		switch (c) {
83			case 'l':
84				status = Load(optarg);
85				break;
86			case 's':
87			case 'o':
88				status = Save(optarg);
89				break;
90			case 'c':
91				status = Copy(optarg);
92				break;
93			case 'r':
94				status = Clear();
95				break;
96			case 'i':
97				status = Copy(NULL);
98				break;
99			case 'p':
100				status = Print(false);
101				break;
102			case 'd':
103				status = Print(true);
104				break;
105			case 0:
106				break;
107			case 'h':
108				// help text is printed in ReadyToRun()
109				return;
110			default:
111				status = B_ERROR;
112				break;
113		}
114	}
115
116	if (status == B_OK)
117		fGotArguments =	true;
118	else
119		sExitValue = EXIT_FAILURE;
120}
121
122
123void
124ClipboardApp::ReadyToRun(void)
125{
126	if (fGotArguments == false)
127		Usage();
128
129	PostMessage(B_QUIT_REQUESTED);
130}
131
132
133void
134ClipboardApp::Usage(void)
135{
136	printf("usage: %s [-olcirpd]\n"
137		"  -s, --save=file\tSave clipboard to file (flattened BMessage)\n"
138		"  -o\t\t\tthe same\n" // ToDo: (\"-\" for standard output/input)\n"
139		"  -l, --load=file\tLoad clipboard from file (flattened BMessage)\n"
140		"  -c, --copy=string\tPut the given string on the clipboard\n"
141		"  -i, --stdin\t\tLoad clipboard with string from standard input\n\n"
142
143		"  -r, --clear\t\tRemove all contents from clipboard\n\n"
144
145		"  -p, --print\t\tPrint clipboard to standard output\n"
146		"  -d, --debug\t\tPrint clipboard message to stdout\n\n"
147
148		"  -h, --help\t\tDisplay this help and exit\n",
149		kProgramName);
150}
151
152
153status_t
154ClipboardApp::Load(const char *path)
155{
156	status_t status = B_OK;
157	BFile file;
158
159	status = file.SetTo(path, B_READ_ONLY);
160	if (status != B_OK) {
161		fprintf(stderr, "%s: Could not open file: %s\n", kProgramName,
162			strerror(status));
163		return status;
164	}
165
166	// get BMessage from file
167	BMessage clipFromFile;
168	status = clipFromFile.Unflatten(&file);
169	if (status != B_OK) {
170		fprintf(stderr, "%s: Could not read clip: %s\n", kProgramName,
171			strerror(status));
172		return status;
173	}
174
175	// load clip into clipboard
176	if (!be_clipboard->Lock()) {
177		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
178		return B_ERROR;
179	}
180
181	be_clipboard->Clear();
182
183	BMessage *clip = be_clipboard->Data();
184	*clip = clipFromFile;
185
186	status = be_clipboard->Commit();
187	if (status != B_OK) {
188		fprintf(stderr, "%s: could not commit data to clipboard.\n",
189			kProgramName);
190		be_clipboard->Unlock();
191		return status;
192	}
193
194	be_clipboard->Unlock();
195	return B_OK;
196}
197
198
199status_t
200ClipboardApp::Save(const char *path)
201{
202	status_t status = B_OK;
203	BFile file;
204
205	status = file.SetTo(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
206	if (status != B_OK) {
207		fprintf(stderr, "%s: Could not create file: %s\n", kProgramName,
208			strerror(status));
209		return status;
210	}
211
212	// get clip
213	if (!be_clipboard->Lock()) {
214		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
215		return B_ERROR;
216	}
217
218	BMessage *clip = be_clipboard->Data();
219
220	be_clipboard->Unlock();
221
222	// flatten clip to file
223	status = clip->Flatten(&file);
224	if (status != B_OK) {
225		fprintf(stderr, "%s: Could not write data: %s\n", kProgramName,
226			strerror(status));
227		return status;
228	}
229
230	return B_OK;
231}
232
233
234status_t
235ClipboardApp::Copy(const char *string)
236{
237	status_t status = B_OK;
238	BString inputString;
239
240	if (string == NULL) {
241		// read from standard input
242		int c;
243		while ((c = fgetc(stdin)) != EOF) {
244			inputString += (char)c;
245		}
246
247		string = inputString.String();
248	}
249
250	// get clipboard BMessage
251
252	if (be_clipboard->Lock()) {
253		be_clipboard->Clear();
254
255		BMessage *clip = be_clipboard->Data();
256
257		// add data to clipboard
258		clip->AddData("text/plain", B_MIME_TYPE, string, strlen(string));
259
260		status = be_clipboard->Commit();
261		if (status != B_OK) {
262			fprintf(stderr, "%s: could not commit data to clipboard.\n",
263				kProgramName);
264			be_clipboard->Unlock();
265			return status;
266		}
267
268		be_clipboard->Unlock();
269	} else {
270		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
271		return B_ERROR;
272	}
273
274	return B_OK;
275}
276
277
278status_t
279ClipboardApp::Clear(void)
280{
281	status_t status = B_OK;
282
283	if (!be_clipboard->Lock()) {
284		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
285		return B_ERROR;
286	}
287
288	be_clipboard->Clear();
289
290	status = be_clipboard->Commit();
291	if (status != B_OK) {
292		fprintf(stderr, "%s: could not clear clipboard.\n", kProgramName);
293		be_clipboard->Unlock();
294		return status;
295	}
296
297	be_clipboard->Unlock();
298	return B_OK;
299}
300
301
302status_t
303ClipboardApp::Print(bool debug)
304{
305	// get clip & print contents
306	// (or the entire clip, in case of --debug)
307
308	if (!be_clipboard->Lock()) {
309		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
310		return B_ERROR;
311	}
312
313	BMessage *clip = be_clipboard->Data();
314
315	if (debug)
316		clip->PrintToStream();
317	else {
318		const char * textBuffer;
319		ssize_t textLength;
320		clip->FindData("text/plain", B_MIME_TYPE, (const void **)&textBuffer,
321			&textLength);
322
323		if (textBuffer != NULL && textLength > 0) {
324			BString textString(textBuffer, textLength);
325			printf("%s\n", textString.String());
326		}
327	}
328
329	be_clipboard->Unlock();
330	return B_OK;
331}
332
333
334//	#pragma mark -
335
336
337int
338main()
339{
340	ClipboardApp clip_app;
341	clip_app.Run();
342
343	return sExitValue;
344}
345
346