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