1 /*
2  *  Copyright 2007-2021 Fabrice Colin
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include <getopt.h>
20 #include <stdlib.h>
21 #include <iostream>
22 #include <string>
23 #include <set>
24 #include <giomm/init.h>
25 #include <glibmm/init.h>
26 
27 #include "config.h"
28 #include "StringManip.h"
29 #include "MIMEScanner.h"
30 #include "Url.h"
31 #include "DBusIndex.h"
32 
33 using namespace std;
34 
35 static struct option g_longOptions[] = {
36 	{"get", 0, 0, 'g'},
37 	{"help", 0, 0, 'h'},
38 	{"list", 0, 0, 'l'},
39 	{"reload", 0, 0, 'r'},
40 	{"set", 1, 0, 's'},
41 	{"version", 0, 0, 'v'},
42 	{0, 0, 0, 0}
43 };
44 
45 
printLabels(const set<string> & labels,const string & fileName)46 static void printLabels(const set<string> &labels, const string &fileName)
47 {
48 	if (fileName.empty() == false)
49 	{
50 		clog << fileName << endl;
51 	}
52 	clog << "Labels: ";
53 
54 	for (set<string>::const_iterator labelIter = labels.begin();
55 		labelIter != labels.end(); ++labelIter)
56 	{
57 		if (labelIter->substr(0, 2) == "X-")
58 		{
59 			continue;
60 		}
61 		clog << "[" << Url::escapeUrl(*labelIter) << "]";
62 	}
63 	clog << endl;
64 }
65 
printHelp(void)66 static void printHelp(void)
67 {
68 	// Help
69 	clog << "pinot-label - Label files from the command-line\n\n"
70 		<< "Usage: pinot-label [OPTIONS] [FILES]\n\n"
71 		<< "Options:\n"
72 		<< "  -g, --get                 get the labels list for the given file\n"
73 		<< "  -h, --help                display this help and exit\n"
74 		<< "  -l, --list                list known labels\n"
75 		<< "  -r, --reload              get the daemon to reload the configuration\n"
76 		<< "  -s, --set                 set labels on the given file\n"
77 		<< "  -v, --version             output version information and exit\n\n";
78 	clog << "Examples:\n"
79 		<< "pinot-label --get /home/fabrice/Documents/Bozo.txt\n\n"
80 		<< "pinot-label --list\n\n"
81 		<< "pinot-label --set \"[Clowns][Fun][My Hero]\" /home/fabrice/Documents/Bozo.txt\n\n"
82 		<< "Report bugs to " << PACKAGE_BUGREPORT << endl;
83 }
84 
main(int argc,char ** argv)85 int main(int argc, char **argv)
86 {
87 	set<string> labels;
88 	string labelsString;
89 	int longOptionIndex = 0;
90 	unsigned int docId = 0;
91 	int minArgNum = 1;
92 	bool getLabels = false, getDocumentLabels = false, reloadIndex = false, setDocumentLabels = false, success = false;
93 
94 	// Look at the options
95 	int optionChar = getopt_long(argc, argv, "ghlrs:v", g_longOptions, &longOptionIndex);
96 	while (optionChar != -1)
97 	{
98 		set<string> engines;
99 
100 		switch (optionChar)
101 		{
102 			case 'g':
103 				getDocumentLabels = true;
104 				break;
105 			case 'h':
106 				printHelp();
107 				return EXIT_SUCCESS;
108 			case 'l':
109 				minArgNum = 0;
110 				getLabels = true;
111 				break;
112 			case 'r':
113 				minArgNum = 0;
114 				reloadIndex = true;
115 				break;
116 			case 's':
117 				setDocumentLabels = true;
118 				if (optarg != NULL)
119 				{
120 					labelsString = optarg;
121 				}
122 				break;
123 			case 'v':
124 				clog << "pinot-label - " << PACKAGE_STRING << "\n\n"
125 					<< "This is free software.  You may redistribute copies of it under the terms of\n"
126 					<< "the GNU General Public License <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.\n"
127 					<< "There is NO WARRANTY, to the extent permitted by law." << endl;
128 				return EXIT_SUCCESS;
129 			default:
130 				return EXIT_FAILURE;
131 		}
132 
133 		// Next option
134 		optionChar = getopt_long(argc, argv, "ghls:v", g_longOptions, &longOptionIndex);
135 	}
136 
137 	if (argc == 1)
138 	{
139 		printHelp();
140 		return EXIT_SUCCESS;
141 	}
142 
143 	if ((argc < 2) ||
144 		(argc - optind < minArgNum))
145 	{
146 		clog << "Not enough parameters" << endl;
147 		return EXIT_FAILURE;
148 	}
149 
150 	if ((setDocumentLabels == true) &&
151 		(labelsString.empty() == true))
152 	{
153 		clog << "Incorrect parameters" << endl;
154 		return EXIT_FAILURE;
155 	}
156 
157 	Glib::init();
158 	Gio::init();
159 	// Initialize GType
160 #if !GLIB_CHECK_VERSION(2,35,0)
161 	g_type_init();
162 #endif
163 
164 	MIMEScanner::initialize("", "");
165 
166 	// We need a pure DBusIndex object
167 	DBusIndex index(NULL);
168 
169 	if (getLabels == true)
170 	{
171 		if (index.getLabels(labels) == true)
172 		{
173 			printLabels(labels, "");
174 
175 			success = true;
176 		}
177 	}
178 
179 	while (optind < argc)
180 	{
181 		string fileParam(argv[optind]);
182 		Url thisUrl(fileParam, "");
183 
184 		// Rewrite it as a local URL
185 		string urlParam(thisUrl.getProtocol());
186 		urlParam += "://";
187 		urlParam += thisUrl.getLocation();
188 		if (thisUrl.getFile().empty() == false)
189 		{
190 			urlParam += "/";
191 			urlParam += thisUrl.getFile();
192 		}
193 #ifdef DEBUG
194 		clog << "URL rewritten to " << urlParam << endl;
195 #endif
196 
197 		if ((getDocumentLabels == true) ||
198 			(setDocumentLabels == true))
199 		{
200 			docId = index.hasDocument(urlParam);
201 			if (docId == 0)
202 			{
203 				clog << fileParam << " is not indexed" << endl;
204 				success = false;
205 
206 				// Next
207 				++optind;
208 				continue;
209 			}
210 		}
211 
212 		if (getDocumentLabels == true)
213 		{
214 			labels.clear();
215 
216 			if (index.getDocumentLabels(docId, labels) == true)
217 			{
218 				printLabels(labels, fileParam);
219 
220 				success = true;
221 			}
222 		}
223 
224 		if (setDocumentLabels == true)
225 		{
226 			string::size_type endPos = 0;
227 			string label(StringManip::extractField(labelsString, "[", "]", endPos));
228 
229 			labels.clear();
230 
231 			// Parse labels
232 			while (label.empty() == false)
233 			{
234 				labels.insert(Url::unescapeUrl(label));
235 
236 				if (endPos == string::npos)
237 				{
238 					break;
239 				}
240 				label = StringManip::extractField(labelsString, "[", "]", endPos);
241 			}
242 
243 #ifdef DEBUG
244 			printLabels(labels, fileParam);
245 #endif
246 			success = index.setDocumentLabels(docId, labels);
247 		}
248 
249 		// Next
250 		++optind;
251 	}
252 
253 	if (reloadIndex == true)
254 	{
255 		index.reload();
256 	}
257 
258 	MIMEScanner::shutdown();
259 
260 	// Did whatever operation we carried out succeed ?
261 	if (success == true)
262 	{
263 		return EXIT_SUCCESS;
264 	}
265 
266 	return EXIT_FAILURE;
267 }
268