1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  Engrampa
5  *
6  *  Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 
27 #include <glib.h>
28 
29 #include "file-data.h"
30 #include "file-utils.h"
31 #include "fr-command.h"
32 #include "fr-command-ar.h"
33 
34 static void fr_command_ar_class_init  (FrCommandArClass *class);
35 static void fr_command_ar_init        (FrCommand        *afile);
36 static void fr_command_ar_finalize    (GObject          *object);
37 
38 /* Parent Class */
39 
40 static FrCommandClass *parent_class = NULL;
41 
42 
43 /* -- list -- */
44 
45 static time_t
mktime_from_string(char * time_s,char * day_s,char * month_s,char * year_s)46 mktime_from_string (char *time_s,
47 		    char *day_s,
48 		    char *month_s,
49 		    char *year_s)
50 {
51 	static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
52 				   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
53 	struct tm    tm = {0, };
54 	char       **fields;
55 
56 	tm.tm_isdst = -1;
57 
58 	/* date */
59 
60 	if (month_s != NULL) {
61 		int i;
62 		for (i = 0; i < 12; i++)
63 			if (strcmp (months[i], month_s) == 0) {
64 				tm.tm_mon = i;
65 				break;
66 			}
67 	}
68 	tm.tm_mday = atoi (day_s);
69 	tm.tm_year = atoi (year_s) - 1900;
70 
71 	/* time */
72 
73 	fields = g_strsplit (time_s, ":", 3);
74 	if (fields[0] != NULL) {
75 		tm.tm_hour = atoi (fields[0]);
76 		if (fields[1] != NULL) {
77 			tm.tm_min  = atoi (fields[1]);
78 			if (fields[2] != NULL)
79 				tm.tm_sec  = atoi (fields[2]);
80 		}
81 	}
82 	g_strfreev (fields);
83 
84 	return mktime (&tm);
85 }
86 
87 
88 static char*
ar_get_last_field(const char * line,int start_from,int field_n)89 ar_get_last_field (const char *line,
90 		   int         start_from,
91 		   int         field_n)
92 {
93 	const char *f_start, *f_end;
94 
95 	line = line + start_from;
96 
97 	f_start = line;
98 	while ((*f_start == ' ') && (*f_start != *line))
99 		f_start++;
100 	f_end = f_start;
101 
102 	while ((field_n > 0) && (*f_end != 0)) {
103 		if (*f_end == ' ') {
104 			field_n--;
105 			if (field_n != 0) {
106 				while ((*f_end == ' ') && (*f_end != *line))
107 					f_end++;
108 				f_start = f_end;
109 			}
110 		} else
111 			f_end++;
112 	}
113 
114 	return g_strdup (f_start);
115 }
116 
117 
118 static void
process_line(char * line,gpointer data)119 process_line (char     *line,
120 	      gpointer  data)
121 {
122 	FileData    *fdata;
123 	FrCommand   *comm = FR_COMMAND (data);
124 	char       **fields;
125 	int          date_idx;
126 	char        *field_month, *field_day, *field_time, *field_year;
127 	char        *field_size, *field_name;
128 
129 	g_return_if_fail (line != NULL);
130 
131 	fdata = file_data_new ();
132 
133 	date_idx = file_list__get_index_from_pattern (line, "%c%c%c %a%n %n%n:%n%n %n%n%n%n");
134 
135 	field_size = file_list__get_prev_field (line, date_idx, 1);
136 	fdata->size = g_ascii_strtoull (field_size, NULL, 10);
137 	g_free (field_size);
138 
139 	field_month = file_list__get_next_field (line, date_idx, 1);
140 	field_day = file_list__get_next_field (line, date_idx, 2);
141 	field_time = file_list__get_next_field (line, date_idx, 3);
142 	field_year = file_list__get_next_field (line, date_idx, 4);
143 	fdata->modified = mktime_from_string (field_time, field_day, field_month, field_year);
144 	g_free (field_day);
145 	g_free (field_month);
146 	g_free (field_year);
147 	g_free (field_time);
148 
149 	/* Full path */
150 
151 	field_name = ar_get_last_field (line, date_idx, 5);
152 
153 	fields = g_strsplit (field_name, " -> ", 2);
154 
155 	if (fields[0] == NULL) {
156 		g_strfreev (fields);
157 		g_free (field_name);
158 		file_data_free (fdata);
159 		return;
160 	}
161 
162 	if (fields[1] == NULL) {
163 		g_strfreev (fields);
164 		fields = g_strsplit (field_name, " link to ", 2);
165 	}
166 
167 	if (*(fields[0]) == '/') {
168 		fdata->full_path = g_strdup (fields[0]);
169 		fdata->original_path = fdata->full_path;
170 	} else {
171 		fdata->full_path = g_strconcat ("/", fields[0], NULL);
172 		fdata->original_path = fdata->full_path + 1;
173 	}
174 
175 	if (fields[1] != NULL)
176 		fdata->link = g_strdup (fields[1]);
177 	g_strfreev (fields);
178 	g_free (field_name);
179 
180 	fdata->name = g_strdup (file_name_from_path (fdata->full_path));
181 	fdata->path = remove_level_from_path (fdata->full_path);
182 
183 	if (*fdata->name == 0)
184 		file_data_free (fdata);
185 	else
186 		fr_command_add_file (comm, fdata);
187 }
188 
189 
190 static void
fr_command_ar_list(FrCommand * comm)191 fr_command_ar_list (FrCommand *comm)
192 {
193 	fr_process_set_out_line_func (comm->process, process_line, comm);
194 
195 	fr_process_begin_command (comm->process, "ar");
196 	fr_process_add_arg (comm->process, "tv");
197 	fr_process_add_arg (comm->process, comm->filename);
198 	fr_process_end_command (comm->process);
199 	fr_process_start (comm->process);
200 }
201 
202 
203 static void
fr_command_ar_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean recursive)204 fr_command_ar_add (FrCommand     *comm,
205 		   const char    *from_file,
206 		   GList         *file_list,
207 		   const char    *base_dir,
208 		   gboolean       update,
209 		   gboolean       recursive)
210 {
211 	GList *scan;
212 
213 	fr_process_begin_command (comm->process, "ar");
214 
215 	if (update)
216 		fr_process_add_arg (comm->process, "ru");
217 	else
218 		fr_process_add_arg (comm->process, "r");
219 
220 	if (base_dir != NULL)
221 		fr_process_set_working_dir (comm->process, base_dir);
222 
223 	fr_process_add_arg (comm->process, comm->filename);
224 
225 	for (scan = file_list; scan; scan = scan->next)
226 		fr_process_add_arg (comm->process, scan->data);
227 
228 	fr_process_end_command (comm->process);
229 }
230 
231 
232 static void
fr_command_ar_delete(FrCommand * comm,const char * from_file,GList * file_list)233 fr_command_ar_delete (FrCommand  *comm,
234 		      const char *from_file,
235 		      GList      *file_list)
236 {
237 	GList *scan;
238 
239 	fr_process_begin_command (comm->process, "ar");
240 	fr_process_add_arg (comm->process, "d");
241 	fr_process_add_arg (comm->process, comm->filename);
242 	for (scan = file_list; scan; scan = scan->next)
243 		fr_process_add_arg (comm->process, scan->data);
244 	fr_process_end_command (comm->process);
245 }
246 
247 
248 static void
fr_command_ar_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)249 fr_command_ar_extract (FrCommand  *comm,
250 		       const char *from_file,
251 		       GList      *file_list,
252 		       const char *dest_dir,
253 		       gboolean    overwrite,
254 		       gboolean    skip_older,
255 		       gboolean    junk_paths)
256 {
257 	GList *scan;
258 
259 	fr_process_begin_command (comm->process, "ar");
260 
261 	if (dest_dir != NULL)
262 		fr_process_set_working_dir (comm->process, dest_dir);
263 
264 	fr_process_add_arg (comm->process, "x");
265 	fr_process_add_arg (comm->process, comm->filename);
266 	for (scan = file_list; scan; scan = scan->next)
267 		fr_process_add_arg (comm->process, scan->data);
268 	fr_process_end_command (comm->process);
269 }
270 
271 
272 static void
fr_command_ar_handle_error(FrCommand * comm,FrProcError * error)273 fr_command_ar_handle_error (FrCommand   *comm,
274 			    FrProcError *error)
275 {
276 	/* FIXME */
277 }
278 
279 
280 const char *ar_mime_type[] = { "application/x-ar",
281 			       "application/x-deb",
282 			       NULL };
283 
284 
285 static const char **
fr_command_ar_get_mime_types(FrCommand * comm)286 fr_command_ar_get_mime_types (FrCommand *comm)
287 {
288 	return ar_mime_type;
289 }
290 
291 
292 static FrCommandCap
fr_command_ar_get_capabilities(FrCommand * comm,const char * mime_type,gboolean check_command)293 fr_command_ar_get_capabilities (FrCommand  *comm,
294 			        const char *mime_type,
295 				gboolean    check_command)
296 {
297 	FrCommandCap capabilities;
298 
299 	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
300 	if (is_program_available ("ar", check_command)) {
301 		if (is_mime_type (mime_type, "application/x-deb"))
302 			capabilities |= FR_COMMAND_CAN_READ;
303 		else if (is_mime_type (mime_type, "application/x-ar"))
304 			capabilities |= FR_COMMAND_CAN_READ_WRITE;
305 	}
306 
307 	return capabilities;
308 }
309 
310 
311 static const char *
fr_command_ar_get_packages(FrCommand * comm,const char * mime_type)312 fr_command_ar_get_packages (FrCommand  *comm,
313 			    const char *mime_type)
314 {
315 	return PACKAGES ("binutils");
316 }
317 
318 
319 static void
fr_command_ar_class_init(FrCommandArClass * class)320 fr_command_ar_class_init (FrCommandArClass *class)
321 {
322         GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
323         FrCommandClass *afc;
324 
325         parent_class = g_type_class_peek_parent (class);
326 	afc = (FrCommandClass*) class;
327 
328 	gobject_class->finalize = fr_command_ar_finalize;
329 
330         afc->list             = fr_command_ar_list;
331 	afc->add              = fr_command_ar_add;
332 	afc->delete_           = fr_command_ar_delete;
333 	afc->extract          = fr_command_ar_extract;
334 	afc->handle_error     = fr_command_ar_handle_error;
335 	afc->get_mime_types   = fr_command_ar_get_mime_types;
336 	afc->get_capabilities = fr_command_ar_get_capabilities;
337 	afc->get_packages     = fr_command_ar_get_packages;
338 }
339 
340 
341 static void
fr_command_ar_init(FrCommand * comm)342 fr_command_ar_init (FrCommand *comm)
343 {
344 	comm->propAddCanUpdate             = TRUE;
345 	comm->propAddCanReplace            = TRUE;
346 	comm->propAddCanStoreFolders       = FALSE;
347 	comm->propExtractCanAvoidOverwrite = FALSE;
348 	comm->propExtractCanSkipOlder      = FALSE;
349 	comm->propExtractCanJunkPaths      = FALSE;
350 	comm->propPassword                 = FALSE;
351 	comm->propTest                     = FALSE;
352 }
353 
354 
355 static void
fr_command_ar_finalize(GObject * object)356 fr_command_ar_finalize (GObject *object)
357 {
358         g_return_if_fail (object != NULL);
359         g_return_if_fail (FR_IS_COMMAND_AR (object));
360 
361 	/* Chain up */
362         if (G_OBJECT_CLASS (parent_class)->finalize)
363 		G_OBJECT_CLASS (parent_class)->finalize (object);
364 }
365 
366 
367 GType
fr_command_ar_get_type()368 fr_command_ar_get_type ()
369 {
370         static GType type = 0;
371 
372         if (! type) {
373                 GTypeInfo type_info = {
374 			sizeof (FrCommandArClass),
375 			NULL,
376 			NULL,
377 			(GClassInitFunc) fr_command_ar_class_init,
378 			NULL,
379 			NULL,
380 			sizeof (FrCommandAr),
381 			0,
382 			(GInstanceInitFunc) fr_command_ar_init
383 		};
384 
385 		type = g_type_register_static (FR_TYPE_COMMAND,
386 					       "FRCommandAr",
387 					       &type_info,
388 					       0);
389         }
390 
391         return type;
392 }
393