1 /*
2  *  Copyright (C) 2017 Ingo Brückl
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 "unar.h"
22 #include "7zip.h"
23 #include "interface.h"
24 #include "main.h"
25 #include "parser.h"
26 #include "string_utils.h"
27 #include "support.h"
28 #include "window.h"
29 
30 #define MAXWIDTH(item, width) (strlen(item) > width ? strlen(item) - width : 0)
31 
32 static gboolean data_line, last_line;
33 
xa_unar_ask(XArchive * archive)34 void xa_unar_ask (XArchive *archive)
35 {
36 	archive->can_test = !(archive->type == XARCHIVETYPE_AR || archive->type == XARCHIVETYPE_COMPRESS || archive->type == XARCHIVETYPE_CPIO || archive->type == XARCHIVETYPE_LZMA || archive->type == XARCHIVETYPE_TAR);
37 	archive->can_extract = (archiver[archive->type].program[1] != NULL);
38 	archive->can_full_path[0] = (archiver[archive->type].program[1] != NULL);
39 	archive->can_overwrite = (archiver[archive->type].program[1] != NULL);
40 }
41 
xa_unar_password_str(XArchive * archive)42 static gchar *xa_unar_password_str (XArchive *archive)
43 {
44 	if (archive->password)
45 		return g_strconcat(" -p ", archive->password, NULL);
46 	else
47 		return g_strdup("");
48 }
49 
xa_unar_parse_output(gchar * line,XArchive * archive)50 static void xa_unar_parse_output (gchar *line, XArchive *archive)
51 {
52 	XEntry *entry;
53 	gpointer item[6];
54 	gchar *index, *flags, *filename;
55 	gboolean dir, encrypted, link;
56 	guint shift;
57 
58 	USE_PARSER;
59 
60 	if (last_line)
61 		return;
62 
63 	if (strncmp(line, "     ", 5) == 0)
64 	{
65 		data_line = TRUE;
66 		return;
67 	}
68 
69 	if (!data_line)
70 	{
71 		if (strstr(line, ": Tar in "))
72 		{
73 			XArchiveType type = archive->type;
74 
75 			xa_get_compressed_tar_type(&type);
76 			archiver[type].program[0] = g_strdup(archiver[archive->type].program[0]);
77 			archiver[type].program[1] = g_strdup(archiver[archive->type].program[1]);
78 			archive->type = type;
79 			archive->can_test = FALSE;
80 		}
81 
82 		return;
83 	}
84 
85 	if (*line == '(')
86 	{
87 		last_line = TRUE;
88 		return;
89 	}
90 
91 	/* index (may exceed column width) */
92 	NEXT_ITEM(index);
93 	shift = MAXWIDTH(index, 4);
94 
95 	/* flags */
96 	NEXT_ITEM(flags);
97 
98 	dir = (flags[0] == 'D');
99 	link = (flags[2] == 'L');
100 	encrypted = (flags[3] == 'E');
101 
102 	if (encrypted)
103 		archive->has_password = TRUE;
104 
105 	/* file size */
106 	NEXT_ITEM(item[1]);
107 
108 	/* ratio (may exceed column width) */
109 	NEXT_ITEM(item[2]);
110 	shift += MAXWIDTH(item[2], 6);
111 
112 	/* mode */
113 	NEXT_ITEM(item[5]);
114 
115 	/* date */
116 	NEXT_ITEM(item[3]);
117 
118 	/* time */
119 	if (strcmp(item[3], "----------------") == 0)
120 	{
121 		char *item3 = (char *) item[3];
122 
123 		item3[10] = 0;
124 		item[4] = item3 + 11;
125 	}
126 	else
127 		NEXT_ITEM(item[4]);
128 
129 	/* name */
130 	LAST_ITEM(filename);
131 	filename += shift;
132 
133 	item[0] = NULL;
134 
135 	if (link)
136 	{
137 		char *l = strstr(filename, " -> ");
138 
139 		if (l)
140 		{
141 			item[0] = l + 4;
142 			*l = 0;
143 		}
144 	}
145 
146 	entry = xa_set_archive_entries_for_each_row(archive, filename, item);
147 
148 	if (entry)
149 	{
150 		if (dir)
151 			entry->is_dir = TRUE;
152 
153 		entry->is_encrypted = encrypted;
154 
155 		if (!entry->is_dir)
156 			archive->files++;
157 
158 		archive->files_size += g_ascii_strtoull(item[1], NULL, 0);
159 	}
160 }
161 
xa_unar_list(XArchive * archive)162 void xa_unar_list (XArchive *archive)
163 {
164 	const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
165 	const gchar *titles[] = {_("Points to"), _("Original Size"), _("Saving"), _("Date"), _("Time"), _("Method")};
166 	gchar *password_str, *command;
167 	guint i;
168 
169 	if (archive->type == XARCHIVETYPE_7ZIP)
170 	{
171 		if (!archive->has_password)
172 			archive->has_password = is7zip_mhe(archive->path[0]);
173 
174 		if (archive->has_password)
175 			if (!xa_check_password(archive))
176 				return;
177 	}
178 
179 	data_line = FALSE;
180 	last_line = FALSE;
181 
182 	archive->files = 0;
183 	archive->files_size = 0;
184 
185 	password_str = xa_unar_password_str(archive);
186 	command = g_strconcat(archiver[archive->type].program[0], " -l", password_str, " ", archive->path[1], NULL);
187 	archive->parse_output = xa_unar_parse_output;
188 	xa_spawn_async_process(archive, command);
189 	g_free(command);
190 	g_free(password_str);
191 
192 	archive->columns = 9;
193 	archive->size_column = 3;
194 	archive->column_types = g_malloc0(sizeof(types));
195 
196 	for (i = 0; i < archive->columns; i++)
197 		archive->column_types[i] = types[i];
198 
199 	xa_create_liststore(archive, titles);
200 }
201 
xa_unar_test(XArchive * archive)202 void xa_unar_test (XArchive *archive)
203 {
204 	gchar *password_str, *command;
205 
206 	password_str = xa_unar_password_str(archive);
207 	command = g_strconcat(archiver[archive->type].program[0], " -t", password_str, " ", archive->path[1], NULL);
208 	g_free(password_str);
209 
210 	xa_run_command(archive, command);
211 	g_free(command);
212 }
213 
xa_unar_extract(XArchive * archive,GSList * file_list)214 gboolean xa_unar_extract (XArchive *archive, GSList *file_list)
215 {
216 	GString *files;
217 	gchar *extract_to, *password_str, *command;
218 	gboolean result;
219 
220 	if (archive->do_full_path)
221 		extract_to = g_strdup(archive->extraction_dir);
222 	else
223 	{
224 		if (!xa_create_working_directory(archive))
225 			return FALSE;
226 
227 		extract_to = g_strconcat(archive->working_dir, "/xa-tmp.XXXXXX", NULL);
228 
229 		if (!g_mkdtemp(extract_to))
230 		{
231 			g_free(extract_to);
232 			return FALSE;
233 		}
234 	}
235 
236 	files = xa_quote_filenames(file_list, "*?[]\"", TRUE);
237 	password_str = xa_unar_password_str(archive);
238 	command = g_strconcat(archiver[archive->type].program[1], " ",
239 	                      archive->path[1], password_str, " -D -q",
240 	                      archive->do_overwrite ? " -f" : "",
241 	                      " -o ", extract_to, files->str, NULL);
242 
243 	result = xa_run_command(archive, command);
244 	g_free(command);
245 
246 	/* collect all files that have been extracted to move them without full path */
247 	if (result && !archive->do_full_path)
248 	{
249 		GString *all_files = xa_collect_files_in_dir(extract_to);
250 
251 		archive->child_dir = g_strdup(extract_to);
252 		command = g_strconcat("mv",
253 		                      archive->do_overwrite ? " -f" : " -n",
254 		                      all_files->str, " ", archive->extraction_dir, NULL);
255 		g_string_free(all_files, TRUE);
256 
257 		result = xa_run_command(archive, command);
258 		g_free(command);
259 
260 		g_free(archive->child_dir);
261 		archive->child_dir = NULL;
262 	}
263 
264 	g_free(extract_to);
265 	g_free(password_str);
266 	g_string_free(files, TRUE);
267 
268 	return result;
269 }
270