1 /*
2  *  Copyright (C) 2008 Giuseppe Torelli - <colossus73@gmail.com>
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., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA 02110-1301 USA.
18  */
19 
20 #include <string.h>
21 #include "arj.h"
22 #include "date_utils.h"
23 #include "main.h"
24 #include "string_utils.h"
25 #include "support.h"
26 #include "window.h"
27 
28 static gboolean data_line, fname_line;
29 
xa_arj_ask(XArchive * archive)30 void xa_arj_ask (XArchive *archive)
31 {
32 	archive->can_test = TRUE;
33 	archive->can_extract = TRUE;
34 	archive->can_add = archiver[archive->type].is_compressor;
35 	archive->can_delete = archiver[archive->type].is_compressor;
36 	archive->can_sfx = archiver[archive->type].is_compressor;
37 	archive->can_password = archiver[archive->type].is_compressor;
38 	archive->can_full_path[0] = archiver[archive->type].is_compressor;
39 	archive->can_full_path[1] = archiver[archive->type].is_compressor;
40 	archive->can_overwrite = TRUE;
41 	archive->can_update[0] = TRUE;
42 	archive->can_update[1] = archiver[archive->type].is_compressor;
43 	archive->can_freshen[0] = archiver[archive->type].is_compressor;
44 	archive->can_freshen[1] = archiver[archive->type].is_compressor;
45 	archive->can_move = archiver[archive->type].is_compressor;
46 }
47 
xa_arj_password_str(XArchive * archive)48 static gchar *xa_arj_password_str (XArchive *archive)
49 {
50 	if (archive->password && archiver[archive->type].is_compressor)
51 		return g_strconcat(" -g", archive->password, NULL);
52 	else
53 		return g_strdup("");
54 }
55 
xa_arj_parse_output(gchar * line,XArchive * archive)56 static void xa_arj_parse_output (gchar *line, XArchive *archive)
57 {
58 	XEntry *entry;
59 	gpointer item[7];
60 	unsigned int linesize,n,a;
61 	static gchar *filename;
62 	gboolean unarj, lfn, dir, encrypted;
63 
64 	unarj = !archiver[archive->type].is_compressor;
65 
66 	if (!data_line)
67 	{
68 		if (line[0] == '-')
69 		{
70 			data_line = TRUE;
71 			return;
72 		}
73 		return;
74 	}
75 
76 	if (!fname_line)
77 	{
78 		linesize = strlen(line);
79 		line[linesize - 1] = '\0';
80 
81 		if (!unarj && (*line == ' '))
82 			return;
83 
84 		if (line[0] == '-' && linesize == (unarj ? 59 : 41))
85 		{
86 			data_line = FALSE;
87 			return;
88 		}
89 
90 		if (unarj)
91 		{
92 			/* simple column separator check */
93 			lfn = (linesize < 76 || line[34] != ' ' || line[40] != ' ' || line[49] != ' ' || line[58] != ' ' || line[67] != ' ');
94 
95 			if (lfn)
96 				filename = g_strdup(line);
97 			else
98 			{
99 				filename = g_strchomp(g_strndup(line, 12));
100 
101 				if (!*filename)
102 				{
103 					g_free(filename);
104 					filename = g_strdup(" ");   // just a wild guess in order to have an entry
105 				}
106 			}
107 		}
108 		else
109 		{
110 			lfn = TRUE;
111 			filename = g_strdup(line + 5);
112 		}
113 
114 		fname_line = TRUE;
115 		if (lfn)
116 			return;
117 	}
118 
119 	if (fname_line)
120 	{
121 		linesize = strlen(line);
122 		/* Size */
123 		for(n=12; n < linesize && line[n] == ' '; n++);
124 		a = n;
125 		for(; n < linesize && line[n] != ' '; n++);
126 		line[n]='\0';
127 		item[0] = line + a;
128 		n++;
129 
130 		/* Compressed */
131 		for(; n < linesize && line[n] == ' '; n++);
132 		a = n;
133 		for(; n < linesize && line[n] != ' '; n++);
134 		line[n]='\0';
135 		item[1] = line + a;
136 		n++;
137 
138 		/* Ratio */
139     	line[40] = '\0';
140     	item[2] = line + 35;
141 
142 		/* Date */
143 		line[49] = '\0';
144 		item[3] = date_YY_MM_DD(line + 41);
145 
146 		/* Time */
147 		line[58] = '\0';
148 		item[4] = line + 50;
149 
150 		/* CRC */
151 		if (unarj)
152 		{
153 			line[67] = '\0';
154 			item[6] = line + 59;
155 		}
156 
157 		/* Permissions */
158 		line[unarj ? 72 : 69] = '\0';
159 		item[5] = line + (unarj ? 68 : 59);
160 
161 		/* BTPMGVX */
162 		if (unarj)
163 		{
164 			dir = (line[73] == 'D');
165 			encrypted = (line[76] == 'G');
166 		}
167 		/* BPMGS */
168 		else
169 		{
170 			dir = (line[59] == 'd');
171 			encrypted = (line[77] == '1');
172 		}
173 
174 		if (encrypted)
175 			archive->has_password = TRUE;
176 
177 		if (unarj && dir)
178 			/* skip entry since unarj lacks directory structure information */
179 			entry = NULL;
180 		else
181 			entry = xa_set_archive_entries_for_each_row(archive, filename, item);
182 
183 		if (entry)
184 		{
185 			if (dir)
186 				entry->is_dir = TRUE;
187 
188 			entry->is_encrypted	= encrypted;
189 
190 			if (!entry->is_dir)
191 				archive->files++;
192 
193 			archive->files_size += g_ascii_strtoull(item[0], NULL, 0);
194 		}
195 
196 		g_free(filename);
197 		fname_line = FALSE;
198 	}
199 }
200 
xa_arj_list(XArchive * archive)201 void xa_arj_list (XArchive *archive)
202 {
203 	const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, archiver[archive->type].is_compressor ? G_TYPE_POINTER : G_TYPE_STRING, G_TYPE_POINTER};
204 	const gchar *titles[] = {_("Original Size"), _("Compressed"), _("Ratio"), _("Date"), _("Time"), archiver[archive->type].is_compressor ? _("Permissions") : _("Attributes"), archiver[archive->type].is_compressor ? NULL : _("Checksum")};
205 	guint i;
206 
207 	data_line = FALSE;
208 	fname_line = FALSE;
209 	gchar *command = g_strconcat(archiver[archive->type].program[0], archiver[archive->type].is_compressor ? " v " : " l ", archive->path[1], NULL);
210 	archive->files_size = 0;
211 	archive->files = 0;
212 	archive->parse_output = xa_arj_parse_output;
213 	xa_spawn_async_process (archive,command);
214 	g_free (command);
215 
216 	archive->columns = (archiver[archive->type].is_compressor ? 9 : 10);
217 	archive->size_column = 2;
218 	archive->column_types = g_malloc0(sizeof(types));
219 
220 	for (i = 0; i < archive->columns; i++)
221 		archive->column_types[i] = types[i];
222 
223 	xa_create_liststore(archive, titles);
224 }
225 
xa_arj_test(XArchive * archive)226 void xa_arj_test (XArchive *archive)
227 {
228 	gchar *password_str, *command;
229 
230 	password_str = xa_arj_password_str(archive);
231 	command = g_strconcat(archiver[archive->type].program[0], " t", password_str, archiver[archive->type].is_compressor ?  " -i -y " : " ", archive->path[1], NULL);
232 	g_free(password_str);
233 
234 	xa_run_command(archive, command);
235 	g_free(command);
236 }
237 
xa_arj_extract(XArchive * archive,GSList * file_list)238 gboolean xa_arj_extract (XArchive *archive, GSList *file_list)
239 {
240 	GString *files;
241 	gchar *command;
242 	gboolean result;
243 
244 	files = xa_quote_filenames(file_list, "*?[]", FALSE);
245 
246 	if (archiver[archive->type].is_compressor)
247 	{
248 		gchar *password_str = xa_arj_password_str(archive);
249 		command = g_strconcat(archiver[archive->type].program[0],
250 		                      archive->do_full_path ? " x" : " e",
251 		                      archive->do_overwrite ? "" : (archive->do_update ? " -u" : (archive->do_freshen ? " -f" : " -n")),
252 		                      password_str, " -i -y ",
253 		                      archive->path[1], " ",
254 		                      archive->extraction_dir, files->str, NULL);
255 		g_free(password_str);
256 	}
257 	else
258 	{
259 		if (xa_create_working_directory(archive))
260 		{
261 			gchar *files_str, *extraction_dir, *archive_path, *move;
262 
263 			files_str = xa_escape_bad_chars(files->str, "\"");
264 			extraction_dir = xa_quote_shell_command(archive->extraction_dir, FALSE);
265 			archive_path = xa_quote_shell_command(archive->path[0], TRUE);
266 
267 			if (strcmp(archive->extraction_dir, archive->working_dir) == 0)
268 				move = g_strdup("");
269 			else
270 				move = g_strconcat(" && mv",
271 				                   archive->do_overwrite ? " -f" : " -n",
272 				                   archive->do_update ? " -fu" : "",
273 				                   *files->str ? files_str : " *", " ",
274 				                   extraction_dir, NULL);
275 
276 			archive->child_dir = g_strdup(archive->working_dir);
277 			command = g_strconcat("sh -c \"rm -f * && ",
278 			                      archiver[archive->type].program[0], " e ",
279 			                      archive_path, move, "\"", NULL);
280 			g_free(move);
281 			g_free(archive_path);
282 			g_free(extraction_dir);
283 			g_free(files_str);
284 		}
285 		else
286 			command = g_strdup("sh -c \"\"");
287 	}
288 
289 	g_string_free(files,TRUE);
290 
291 	result = xa_run_command(archive, command);
292 	g_free(command);
293 
294 	g_free(archive->child_dir);
295 	archive->child_dir = NULL;
296 
297 	return result;
298 }
299 
xa_arj_add(XArchive * archive,GSList * file_list,gchar * compression)300 void xa_arj_add (XArchive *archive, GSList *file_list, gchar *compression)
301 {
302 	GString *files;
303 	gchar *password_str, *command;
304 
305 	if (archive->location_path != NULL)
306 		archive->child_dir = g_strdup(archive->working_dir);
307 
308 	if (!compression)
309 		compression = "1";
310 
311 	files = xa_quote_filenames(file_list, "*?[]", FALSE);
312 	password_str = xa_arj_password_str(archive);
313 	command = g_strconcat(archiver[archive->type].program[0],
314 	                      archive->do_update ? " u" : " a",
315 	                      archive->do_freshen ? " -f" : "",
316 	                      archive->do_move ? " -d1" : "",
317 	                      " -m", compression,
318 	                      password_str, " -2d -i -y ",
319 	                      archive->path[1], files->str, NULL);
320 	g_free(password_str);
321 	g_string_free(files,TRUE);
322 
323 	xa_run_command(archive, command);
324 	g_free(command);
325 }
326 
xa_arj_delete(XArchive * archive,GSList * file_list)327 void xa_arj_delete (XArchive *archive, GSList *file_list)
328 {
329 	GString *files;
330 	gchar *command;
331 
332 	files = xa_quote_filenames(file_list, "*?[]", FALSE);
333 	command = g_strconcat(archiver[archive->type].program[0], " d -i -y ", archive->path[1], files->str, NULL);
334 	g_string_free(files,TRUE);
335 
336 	xa_run_command(archive, command);
337 	g_free(command);
338 }
339