summaryrefslogtreecommitdiff
path: root/src/bin/ethumb_client
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2013-01-15 18:10:58 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2013-01-15 18:10:58 +0000
commitd97c63e4c69d0a8c3cb29b22927b5b53c7bf46c4 (patch)
tree4309480b1cb48058bdac139f6eb14cbeaf515fd6 /src/bin/ethumb_client
parent028e7e9ed2ca4aad0dd04493019d495f68fa6a31 (diff)
fix directory structure: move ethumd_client out of ethumb.
it's another library, do not mix stuff as it used to be. SVN revision: 82835
Diffstat (limited to 'src/bin/ethumb_client')
-rw-r--r--src/bin/ethumb_client/ethumbd.c1805
-rw-r--r--src/bin/ethumb_client/ethumbd_client.c330
-rw-r--r--src/bin/ethumb_client/ethumbd_private.h41
-rw-r--r--src/bin/ethumb_client/ethumbd_slave.c770
4 files changed, 2946 insertions, 0 deletions
diff --git a/src/bin/ethumb_client/ethumbd.c b/src/bin/ethumb_client/ethumbd.c
new file mode 100644
index 0000000000..a68aed618c
--- /dev/null
+++ b/src/bin/ethumb_client/ethumbd.c
@@ -0,0 +1,1805 @@
1/**
2 * @file
3 *
4 * Copyright (C) 2009 by ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library;
18 * if not, see <http://www.gnu.org/licenses/>.
19 *
20 * @author Rafael Antognolli <antognolli@profusion.mobi>
21 */
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <limits.h>
30#include <unistd.h>
31#include <errno.h>
32
33#include <Eina.h>
34#include <Ecore_Getopt.h>
35#include <Ecore.h>
36#include <EDBus.h>
37#include <Ethumb.h>
38#include <Ethumb_Client.h>
39
40#include "ethumbd_private.h"
41
42#ifndef PATH_MAX
43#define PATH_MAX 4096
44#endif
45
46#define MAX_ID 2000000
47#define DAEMON "daemon"
48#define ODATA "odata"
49
50#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
51#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
52#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
53#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
54#define CRIT(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
55
56static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
57static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
58static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
59static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
60
61static Eina_Prefix *_pfx = NULL;
62static int _log_domain = -1;
63
64typedef struct _Ethumbd_Setup Ethumbd_Setup;
65typedef struct _Ethumbd_Slave Ethumbd_Slave;
66typedef struct _Ethumbd_Request Ethumbd_Request;
67typedef struct _Ethumbd_Queue Ethumbd_Queue;
68typedef struct _Ethumbd_Object Ethumbd_Object;
69typedef struct _Ethumbd_Object_Data Ethumbd_Object_Data;
70typedef struct _Ethumbd Ethumbd;
71
72struct _Ethumbd_Setup
73{
74 struct
75 {
76 Eina_Bool fdo : 1;
77 Eina_Bool size : 1;
78 Eina_Bool format : 1;
79 Eina_Bool aspect : 1;
80 Eina_Bool orientation: 1;
81 Eina_Bool crop : 1;
82 Eina_Bool quality : 1;
83 Eina_Bool compress : 1;
84 Eina_Bool directory : 1;
85 Eina_Bool category : 1;
86 Eina_Bool frame : 1;
87 Eina_Bool video_time : 1;
88 Eina_Bool video_start : 1;
89 Eina_Bool video_interval : 1;
90 Eina_Bool video_ntimes : 1;
91 Eina_Bool video_fps : 1;
92 Eina_Bool document_page : 1;
93 } flags;
94 int fdo;
95 int tw, th;
96 int format;
97 int aspect;
98 int orientation;
99 float cx, cy;
100 int quality;
101 int compress;
102 const char *directory;
103 const char *category;
104 const char *theme_file;
105 const char *group;
106 const char *swallow;
107 float video_time;
108 float video_start;
109 float video_interval;
110 unsigned int video_ntimes;
111 unsigned int video_fps;
112 unsigned int document_page;
113};
114
115struct _Ethumbd_Request
116{
117 int id;
118 const char *file, *key;
119 const char *thumb, *thumb_key;
120 Ethumbd_Setup setup;
121};
122
123struct _Ethumbd_Object
124{
125 int used;
126 const char *path;
127 const char *client;
128 Eina_List *queue;
129 int nqueue;
130 int id_count;
131 int max_id;
132 int min_id;
133 EDBus_Service_Interface *iface;
134};
135
136struct _Ethumbd_Queue
137{
138 int count;
139 int max_count;
140 int nqueue;
141 int last;
142 int current;
143 Ethumbd_Object *table;
144 int *list;
145};
146
147struct _Ethumbd_Slave
148{
149 Ecore_Exe *exe;
150 char *bufcmd; // buffer to read commands from slave
151 int scmd; // size of command to read
152 int pcmd; // position in the command buffer
153};
154
155struct _Ethumbd
156{
157 EDBus_Connection *conn;
158 Ecore_Idler *idler;
159 Ethumbd_Request *processing;
160 Ethumbd_Queue queue;
161 double timeout;
162 Ecore_Timer *timeout_timer;
163 Ethumbd_Slave slave;
164
165 Ecore_Event_Handler *data_cb;
166 Ecore_Event_Handler *del_cb;
167};
168
169struct _Ethumbd_Object_Data
170{
171 int idx;
172 Ethumbd *ed;
173};
174
175const Ecore_Getopt optdesc = {
176 "ethumbd",
177 NULL,
178 PACKAGE_VERSION,
179 "(C) 2009 - ProFUSION embedded systems",
180 "LGPL v2.1 - GNU Lesser General Public License",
181 "Ethumb daemon.\n"
182 "\n"
183 "ethumbd uses the Ethumb library to create thumbnails for any "
184 "program that requests it (now just by dbus).\n",
185 0,
186 {
187 ECORE_GETOPT_STORE_DOUBLE
188 ('t', "timeout", "finish ethumbd after <timeout> seconds of no activity."),
189 ECORE_GETOPT_LICENSE('L', "license"),
190 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
191 ECORE_GETOPT_VERSION('V', "version"),
192 ECORE_GETOPT_HELP('h', "help"),
193 ECORE_GETOPT_SENTINEL
194 }
195};
196
197static EDBus_Message *_ethumb_dbus_queue_add_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg);
198static EDBus_Message *_ethumb_dbus_queue_remove_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg);
199static EDBus_Message *_ethumb_dbus_queue_clear_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg);
200static EDBus_Message *_ethumb_dbus_ethumb_setup_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg);
201static EDBus_Message *_ethumb_dbus_delete_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg);
202
203static const EDBus_Method _ethumb_dbus_objects_methods[] = {
204 {
205 "queue_add",
206 EDBUS_ARGS({"i", "id"}, {"ay", "file"}, {"ay", "key"}, {"ay", "thumb"}, {"ay", "thumb_key"}),
207 EDBUS_ARGS({"i", "queue_id"}), _ethumb_dbus_queue_add_cb, 0
208 },
209 {
210 "queue_remove", EDBUS_ARGS({"i", "queue_id"}), EDBUS_ARGS({"b", "result"}),
211 _ethumb_dbus_queue_remove_cb, 0
212 },
213 {
214 "clear_queue", NULL, NULL, _ethumb_dbus_queue_clear_cb, 0
215 },
216 {
217 "ethumb_setup", EDBUS_ARGS({"a{sv}", "array"}), EDBUS_ARGS({"b", "result"}),
218 _ethumb_dbus_ethumb_setup_cb, 0
219 },
220 {
221 "delete", NULL, NULL, _ethumb_dbus_delete_cb, 0
222 },
223 { }
224};
225
226enum
227{
228 ETHUMB_DBUS_OBJECTS_SIGNAL_GENERATED = 0,
229};
230
231static const EDBus_Signal _ethumb_dbus_objects_signals[] = {
232 [ETHUMB_DBUS_OBJECTS_SIGNAL_GENERATED] = { "generated",
233 EDBUS_ARGS({ "i", "id" }, { "ay", "paths" }, { "ay", "keys" },
234 { "b", "success" }) },
235 { }
236};
237
238static void _ethumb_dbus_generated_signal(Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success);
239static Eina_Bool _ethumbd_slave_spawn(Ethumbd_Slave *slave, Ethumbd *ed);
240
241static Eina_Bool
242_ethumbd_timeout_cb(void *data)
243{
244 Ethumbd *ed = data;
245
246 ecore_main_loop_quit();
247 ed->timeout_timer = NULL;
248
249 return 0;
250}
251
252static void
253_ethumbd_timeout_start(Ethumbd *ed)
254{
255 if (ed->timeout < 0)
256 return;
257
258 if (!ed->timeout_timer)
259 ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed);
260}
261
262static void
263_ethumbd_timeout_stop(Ethumbd *ed)
264{
265 if (!ed->timeout_timer)
266 return;
267
268 ecore_timer_del(ed->timeout_timer);
269 ed->timeout_timer = NULL;
270}
271
272static int
273_ethumb_dbus_check_id(Ethumbd_Object *eobject, int id)
274{
275 if (id < 0 || id > MAX_ID)
276 return 0;
277
278 if (eobject->min_id < eobject->max_id)
279 return id < eobject->min_id || id > eobject->max_id;
280 else if (eobject->min_id > eobject->max_id)
281 return id < eobject->min_id && id > eobject->max_id;
282 else
283 return id != eobject->max_id;
284}
285
286static void
287_ethumb_dbus_inc_max_id(Ethumbd_Object *eobject, int id)
288{
289 if (eobject->min_id < 0 && eobject->max_id < 0)
290 eobject->min_id = id;
291
292 eobject->max_id = id;
293}
294
295static void
296_ethumb_dbus_inc_min_id(Ethumbd_Object *eobject)
297{
298 Eina_List *l;
299
300 l = eobject->queue;
301 while (l)
302 {
303 Ethumbd_Request *request = l->data;
304 if (request->id >= 0)
305 {
306 eobject->min_id = request->id;
307 break;
308 }
309
310 l = l->next;
311 }
312
313 if (!l)
314 {
315 eobject->min_id = -1;
316 eobject->max_id = -1;
317 }
318}
319
320int
321_ethumbd_write_safe(Ethumbd_Slave *slave, const void *buf, ssize_t size)
322{
323
324 if (!slave->exe)
325 {
326 ERR("slave process isn't running.");
327 return 0;
328 }
329
330 ecore_exe_send(slave->exe, buf, size);
331 return 1;
332}
333
334static void
335_ethumbd_child_write_op_new(Ethumbd_Slave *slave, int idx)
336{
337 int id = ETHUMBD_OP_NEW;
338 _ethumbd_write_safe(slave, &id, sizeof(id));
339 _ethumbd_write_safe(slave, &idx, sizeof(idx));
340}
341
342static void
343_ethumbd_child_write_op_del(Ethumbd_Slave *slave, int idx)
344{
345 int id = ETHUMBD_OP_DEL;
346 _ethumbd_write_safe(slave, &id, sizeof(id));
347 _ethumbd_write_safe(slave, &idx, sizeof(idx));
348}
349
350static void
351_ethumbd_pipe_str_write(Ethumbd_Slave *slave, const char *str)
352{
353 int len;
354
355 if (str)
356 len = strlen(str) + 1;
357 else
358 len = 0;
359
360 _ethumbd_write_safe(slave, &len, sizeof(len));
361 _ethumbd_write_safe(slave, str, len);
362}
363
364static void
365_ethumbd_child_write_op_generate(Ethumbd_Slave *slave,
366 int idx, const char *path, const char *key,
367 const char *thumb_path, const char *thumb_key)
368{
369 int id = ETHUMBD_OP_GENERATE;
370
371 _ethumbd_write_safe(slave, &id, sizeof(id));
372 _ethumbd_write_safe(slave, &idx, sizeof(idx));
373
374 _ethumbd_pipe_str_write(slave, path);
375 _ethumbd_pipe_str_write(slave, key);
376 _ethumbd_pipe_str_write(slave, thumb_path);
377 _ethumbd_pipe_str_write(slave, thumb_key);
378}
379
380static void
381_generated_cb(Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key)
382{
383 int i = ed->queue.current;
384
385 DBG("thumbnail ready at: \"%s:%s\"", thumb_path, thumb_key);
386
387 if (ed->queue.table[i].used)
388 _ethumb_dbus_generated_signal
389 (ed, &ed->processing->id, thumb_path, thumb_key, success);
390 eina_stringshare_del(ed->processing->file);
391 eina_stringshare_del(ed->processing->key);
392 eina_stringshare_del(ed->processing->thumb);
393 eina_stringshare_del(ed->processing->thumb_key);
394 free(ed->processing);
395 ed->processing = NULL;
396}
397
398static void
399_ethumbd_slave_cmd_ready(Ethumbd *ed)
400{
401 const char *bufcmd = ed->slave.bufcmd;
402 Eina_Bool success;
403 const char *thumb_path = NULL;
404 const char *thumb_key = NULL;
405 int size_path, size_key;
406
407 /* NOTE: accessing values directly on bufcmd breaks alignment
408 * as the first item is an Eina_Bool (size 1) and second is
409 * an integer (size 4, alignment 4).
410 * Thus copy to stack values before using them, to have proper alignment.
411 */
412#define READVAL(dst) \
413 memcpy(&dst, bufcmd, sizeof(dst)); \
414 bufcmd += sizeof(dst);
415
416 READVAL(success);
417
418 READVAL(size_path);
419 if (size_path)
420 {
421 thumb_path = bufcmd;
422 bufcmd += size_path;
423 }
424
425 READVAL(size_key);
426 if (size_key) thumb_key = bufcmd;
427
428#undef READVAL
429
430 _generated_cb(ed, success, thumb_path, thumb_key);
431
432 free(ed->slave.bufcmd);
433 ed->slave.bufcmd = NULL;
434 ed->slave.scmd = 0;
435}
436
437static int
438_ethumbd_slave_alloc_cmd(Ethumbd *ed, int ssize, char *sdata)
439{
440 int *scmd;
441
442 if (ed->slave.bufcmd)
443 return 0;
444
445 scmd = (int *)sdata;
446 if (ssize < (int)sizeof(*scmd)) {
447 ERR("could not read size of command.");
448 return 0;
449 }
450 ed->slave.bufcmd = malloc(*scmd);
451 ed->slave.scmd = *scmd;
452 ed->slave.pcmd = 0;
453
454 return sizeof(*scmd);
455}
456
457static Eina_Bool
458_ethumbd_slave_data_read_cb(void *data, int type EINA_UNUSED, void *event)
459{
460 Ethumbd *ed = data;
461 Ecore_Exe_Event_Data *ev = event;
462 int ssize;
463 char *sdata;
464
465 if (ev->exe != ed->slave.exe)
466 {
467 ERR("PARENT ERROR: slave != ev->exe");
468 return 0;
469 }
470
471 ssize = ev->size;
472 sdata = ev->data;
473
474 while (ssize > 0)
475 {
476 if (!ed->slave.bufcmd)
477 {
478 int n;
479 n = _ethumbd_slave_alloc_cmd(ed, ssize, sdata);
480 ssize -= n;
481 sdata += n;
482 }
483 else
484 {
485 char *bdata;
486 int nbytes;
487 bdata = ed->slave.bufcmd + ed->slave.pcmd;
488 nbytes = ed->slave.scmd - ed->slave.pcmd;
489 nbytes = ssize < nbytes ? ssize : nbytes;
490 memcpy(bdata, sdata, nbytes);
491 sdata += nbytes;
492 ssize -= nbytes;
493 ed->slave.pcmd += nbytes;
494
495 if (ed->slave.pcmd == ed->slave.scmd)
496 _ethumbd_slave_cmd_ready(ed);
497 }
498 }
499
500 return 1;
501}
502
503static Eina_Bool
504_ethumbd_slave_del_cb(void *data, int type EINA_UNUSED, void *event)
505{
506 Ethumbd *ed = data;
507 Ecore_Exe_Event_Del *ev = event;
508 int i;
509
510 if (ev->exe != ed->slave.exe)
511 return 1;
512
513 if (ev->exited)
514 ERR("slave exited with code: %d", ev->exit_code);
515 else if (ev->signalled)
516 ERR("slave exited by signal: %d", ev->exit_signal);
517
518 if (!ed->processing)
519 goto end;
520
521 i = ed->queue.current;
522 ERR("failed to generate thumbnail for: \"%s:%s\"",
523 ed->processing->file, ed->processing->key);
524
525 if (ed->queue.table[i].used)
526 _ethumb_dbus_generated_signal
527 (ed, &ed->processing->id, NULL, NULL, EINA_FALSE);
528 eina_stringshare_del(ed->processing->file);
529 eina_stringshare_del(ed->processing->key);
530 eina_stringshare_del(ed->processing->thumb);
531 eina_stringshare_del(ed->processing->thumb_key);
532 free(ed->processing);
533 ed->processing = NULL;
534
535end:
536 ed->slave.exe = NULL;
537 if (ed->slave.bufcmd)
538 free(ed->slave.bufcmd);
539
540 if (!_ethumbd_slave_spawn(&ed->slave, ed))
541 return EINA_FALSE;
542
543 /* restart all queue */
544 for (i = 0; i < ed->queue.count; ++i)
545 _ethumbd_child_write_op_new(&ed->slave, ed->queue.list[i]);
546
547 return EINA_TRUE;
548}
549
550static void
551_ethumbd_pipe_write_setup(Ethumbd_Slave *slave, int type, const void *data)
552{
553 const int *i_value;
554 const float *f_value;
555
556 _ethumbd_write_safe(slave, &type, sizeof(type));
557
558 switch (type)
559 {
560 case ETHUMBD_FDO:
561 case ETHUMBD_FORMAT:
562 case ETHUMBD_ASPECT:
563 case ETHUMBD_ORIENTATION:
564 case ETHUMBD_QUALITY:
565 case ETHUMBD_COMPRESS:
566 case ETHUMBD_SIZE_W:
567 case ETHUMBD_SIZE_H:
568 case ETHUMBD_DOCUMENT_PAGE:
569 case ETHUMBD_VIDEO_NTIMES:
570 case ETHUMBD_VIDEO_FPS:
571 i_value = data;
572 _ethumbd_write_safe(slave, i_value, sizeof(*i_value));
573 break;
574 case ETHUMBD_CROP_X:
575 case ETHUMBD_CROP_Y:
576 case ETHUMBD_VIDEO_TIME:
577 case ETHUMBD_VIDEO_START:
578 case ETHUMBD_VIDEO_INTERVAL:
579 f_value = data;
580 _ethumbd_write_safe(slave, f_value, sizeof(*f_value));
581 break;
582 case ETHUMBD_DIRECTORY:
583 case ETHUMBD_CATEGORY:
584 case ETHUMBD_FRAME_FILE:
585 case ETHUMBD_FRAME_GROUP:
586 case ETHUMBD_FRAME_SWALLOW:
587 _ethumbd_pipe_str_write(slave, data);
588 break;
589 case ETHUMBD_SETUP_FINISHED:
590 break;
591 default:
592 ERR("wrong ethumb setup parameter.");
593 }
594}
595
596static void
597_process_setup(Ethumbd *ed)
598{
599 int op_id = ETHUMBD_OP_SETUP;
600 int idx = ed->queue.current;
601
602 Ethumbd_Setup *setup = &ed->processing->setup;
603 Ethumbd_Slave *slave = &ed->slave;
604
605 _ethumbd_write_safe(slave, &op_id, sizeof(op_id));
606 _ethumbd_write_safe(slave, &idx, sizeof(idx));
607
608 if (setup->flags.fdo)
609 _ethumbd_pipe_write_setup(slave, ETHUMBD_FDO, &setup->fdo);
610 if (setup->flags.size)
611 {
612 _ethumbd_pipe_write_setup(slave, ETHUMBD_SIZE_W, &setup->tw);
613 _ethumbd_pipe_write_setup(slave, ETHUMBD_SIZE_H, &setup->th);
614 }
615 if (setup->flags.format)
616 _ethumbd_pipe_write_setup(slave, ETHUMBD_FORMAT, &setup->format);
617 if (setup->flags.aspect)
618 _ethumbd_pipe_write_setup(slave, ETHUMBD_ASPECT, &setup->aspect);
619 if (setup->flags.orientation)
620 _ethumbd_pipe_write_setup(slave, ETHUMBD_ORIENTATION, &setup->orientation);
621 if (setup->flags.crop)
622 {
623 _ethumbd_pipe_write_setup(slave, ETHUMBD_CROP_X, &setup->cx);
624 _ethumbd_pipe_write_setup(slave, ETHUMBD_CROP_Y, &setup->cy);
625 }
626 if (setup->flags.quality)
627 _ethumbd_pipe_write_setup(slave, ETHUMBD_QUALITY, &setup->quality);
628 if (setup->flags.compress)
629 _ethumbd_pipe_write_setup(slave, ETHUMBD_COMPRESS, &setup->compress);
630 if (setup->flags.directory)
631 _ethumbd_pipe_write_setup(slave, ETHUMBD_DIRECTORY, setup->directory);
632 if (setup->flags.category)
633 _ethumbd_pipe_write_setup(slave, ETHUMBD_CATEGORY, setup->category);
634 if (setup->flags.frame)
635 {
636 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_FILE, setup->theme_file);
637 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_GROUP, setup->group);
638 _ethumbd_pipe_write_setup(slave, ETHUMBD_FRAME_SWALLOW, setup->swallow);
639 }
640 if (setup->flags.video_time)
641 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_TIME, &setup->video_time);
642 if (setup->flags.video_start)
643 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_START, &setup->video_start);
644 if (setup->flags.video_interval)
645 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_INTERVAL,
646 &setup->video_interval);
647 if (setup->flags.video_ntimes)
648 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
649 if (setup->flags.video_fps)
650 _ethumbd_pipe_write_setup(slave, ETHUMBD_VIDEO_FPS, &setup->video_fps);
651 if (setup->flags.document_page)
652 _ethumbd_pipe_write_setup(slave, ETHUMBD_DOCUMENT_PAGE,
653 &setup->document_page);
654 _ethumbd_pipe_write_setup(slave, ETHUMBD_SETUP_FINISHED, NULL);
655
656
657 if (setup->directory) eina_stringshare_del(setup->directory);
658 if (setup->category) eina_stringshare_del(setup->category);
659 if (setup->theme_file) eina_stringshare_del(setup->theme_file);
660 if (setup->group) eina_stringshare_del(setup->group);
661 if (setup->swallow) eina_stringshare_del(setup->swallow);
662
663 free(ed->processing);
664 ed->processing = NULL;
665}
666
667static void
668_process_file(Ethumbd *ed)
669{
670 _ethumbd_child_write_op_generate
671 (&ed->slave, ed->queue.current, ed->processing->file,
672 ed->processing->key, ed->processing->thumb, ed->processing->thumb_key);
673}
674
675static int
676_get_next_on_queue(Ethumbd_Queue *queue)
677{
678 int i, idx;
679 Ethumbd_Object *eobject;
680
681 i = queue->last;
682 i++;
683 if (i >= queue->count)
684 i = 0;
685
686 idx = queue->list[i];
687 eobject = &(queue->table[idx]);
688 while (!eobject->nqueue)
689 {
690 i = (i + 1) % queue->count;
691
692 idx = queue->list[i];
693 eobject = &(queue->table[idx]);
694 }
695
696 return queue->list[i];
697}
698
699static Eina_Bool
700_process_queue_cb(void *data)
701{
702 Ethumbd_Object *eobject;
703 int i;
704 Ethumbd *ed = data;
705 Ethumbd_Queue *queue = &ed->queue;
706 Ethumbd_Request *request;
707
708 if (ed->processing)
709 return 1;
710
711 if (!queue->nqueue)
712 {
713 ed->idler = NULL;
714 if (!queue->count)
715 _ethumbd_timeout_start(ed);
716 ed->idler = NULL;
717 return 0;
718 }
719
720 i = _get_next_on_queue(queue);
721 eobject = &(queue->table[i]);
722
723 request = eina_list_data_get(eobject->queue);
724 eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue);
725 ed->queue.current = i;
726 DBG("processing file: \"%s:%s\"...", request->file,
727 request->key);
728 ed->processing = request;
729
730 if (request->id < 0)
731 _process_setup(ed);
732 else
733 {
734 _process_file(ed);
735 _ethumb_dbus_inc_min_id(eobject);
736 }
737 eobject->nqueue--;
738 queue->nqueue--;
739
740 queue->last = i;
741
742 return 1;
743}
744
745static void
746_process_queue_start(Ethumbd *ed)
747{
748 if (!ed->idler)
749 ed->idler = ecore_idler_add(_process_queue_cb, ed);
750}
751
752static void
753_process_queue_stop(Ethumbd *ed)
754{
755 if (ed->idler)
756 {
757 ecore_idler_del(ed->idler);
758 ed->idler = NULL;
759 }
760}
761
762static int
763_ethumb_table_append(Ethumbd *ed)
764{
765 int i;
766 char buf[1024];
767 Ethumbd_Queue *q = &ed->queue;
768
769 if (q->count == q->max_count)
770 {
771 int new_max = q->max_count + 5;
772 int start, size;
773 void *tmp;
774
775 start = q->max_count;
776 size = new_max - q->max_count;
777
778 tmp = realloc(q->table, new_max * sizeof(Ethumbd_Object));
779 if (!tmp)
780 {
781 CRIT("could not realloc q->table to %zd bytes: %s",
782 new_max * sizeof(Ethumbd_Object), strerror(errno));
783 return -1;
784 }
785 q->table = tmp;
786 memset(&q->table[start], 0, size * sizeof(Ethumbd_Object));
787
788 tmp = realloc(q->list, new_max * sizeof(int));
789 if (!tmp)
790 {
791 CRIT("could not realloc q->list to %zd bytes: %s",
792 new_max * sizeof(int), strerror(errno));
793 return -1;
794 }
795 q->list = tmp;
796
797 q->max_count = new_max;
798 }
799
800 for (i = 0; i < q->max_count; i++)
801 {
802 if (!q->table[i].used)
803 break;
804 }
805
806 snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i);
807 q->table[i].used = 1;
808 q->table[i].path = eina_stringshare_add(buf);
809 q->table[i].max_id = -1;
810 q->table[i].min_id = -1;
811 q->list[q->count] = i;
812 q->count++;
813 DBG("new object: %s, idx = %d, count = %d", buf, i, q->count);
814
815 return i;
816}
817
818static inline int
819_get_idx_for_path(const char *path)
820{
821 int i;
822 int n;
823 n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i);
824 if (!n)
825 return -1;
826 return i;
827}
828
829static void _name_owner_changed_cb(void *context, const char *bus, const char *old_id, const char *new_id);
830
831static void
832_ethumb_table_del(Ethumbd *ed, int i)
833{
834 int j;
835 Eina_List *l;
836 Ethumbd_Queue *q = &ed->queue;
837 Ethumbd_Object_Data *odata;
838
839 eina_stringshare_del(q->table[i].path);
840
841 l = q->table[i].queue;
842 while (l)
843 {
844 Ethumbd_Request *request = l->data;
845 eina_stringshare_del(request->file);
846 eina_stringshare_del(request->key);
847 eina_stringshare_del(request->thumb);
848 eina_stringshare_del(request->thumb_key);
849 free(request);
850 l = eina_list_remove_list(l, l);
851 }
852 q->nqueue -= q->table[i].nqueue;
853
854 odata = edbus_service_object_data_del(q->table[i].iface, ODATA);
855 edbus_name_owner_changed_callback_del(ed->conn, ed->queue.table[i].client,
856 _name_owner_changed_cb, odata);
857 //this string was not been freed previously
858 eina_stringshare_del(ed->queue.table[i].client);
859 free(odata);
860 edbus_service_object_unregister(q->table[i].iface);
861
862 memset(&(q->table[i]), 0, sizeof(Ethumbd_Object));
863 for (j = 0; j < q->count; j++)
864 {
865 if (q->list[j] == i)
866 q->list[j] = q->list[q->count - 1];
867 }
868
869 q->count--;
870 _ethumbd_child_write_op_del(&ed->slave, i);
871 if (!q->count && !ed->processing)
872 _ethumbd_timeout_start(ed);
873}
874
875static void
876_ethumb_table_clear(Ethumbd *ed)
877{
878 int i;
879
880 for (i = 0; i < ed->queue.max_count; i++)
881 if (ed->queue.table[i].used)
882 _ethumb_table_del(ed, i);
883}
884
885static void
886_name_owner_changed_cb(void *context, const char *bus, const char *old_id, const char *new_id)
887{
888 Ethumbd_Object_Data *odata = context;
889 Ethumbd *ed = odata->ed;
890
891 DBG("NameOwnerChanged: name = %s, from = %s, to = %s", bus, old_id, new_id);
892 if (new_id[0])
893 return;
894 _ethumb_table_del(ed, odata->idx);
895}
896
897static const EDBus_Service_Interface_Desc client_desc = {
898 _ethumb_dbus_objects_interface, _ethumb_dbus_objects_methods,
899 _ethumb_dbus_objects_signals
900};
901
902static EDBus_Message *
903_ethumb_dbus_ethumb_new_cb(const EDBus_Service_Interface *interface, const EDBus_Message *msg)
904{
905 EDBus_Message *reply;
906 EDBus_Service_Interface *iface;
907 Ethumbd_Object_Data *odata;
908 int i;
909 const char *return_path = "";
910 const char *client;
911 Ethumbd *ed;
912
913 ed = edbus_service_object_data_get(interface, DAEMON);
914 client = edbus_message_sender_get(msg);
915 if (!client)
916 goto end_new;
917
918 i = _ethumb_table_append(ed);
919 if (i < 0)
920 goto end_new;
921
922 odata = calloc(1, sizeof(*odata));
923 odata->idx = i;
924 odata->ed = ed;
925
926 ed->queue.table[i].client = eina_stringshare_add(client);
927 return_path = ed->queue.table[i].path;
928
929 iface = edbus_service_interface_register(ed->conn, return_path, &client_desc);
930 if (!iface)
931 {
932 ERR("could not create dbus_object.");
933 free(odata);
934 return_path = "";
935 goto end_new;
936 }
937 edbus_service_object_data_set(iface, ODATA, odata);
938 ed->queue.table[i].iface = iface;
939 edbus_name_owner_changed_callback_add(ed->conn, client,
940 _name_owner_changed_cb, odata,
941 EINA_TRUE);
942 _ethumbd_child_write_op_new(&ed->slave, i);
943 _ethumbd_timeout_stop(ed);
944
945 end_new:
946 reply = edbus_message_method_return_new(msg);
947 edbus_message_arguments_append(reply, "o", return_path);
948 return reply;
949}
950
951static const EDBus_Method _ethumb_dbus_methods[] = {
952 {
953 "new", NULL, EDBUS_ARGS({"o", "path"}), _ethumb_dbus_ethumb_new_cb, 0
954 },
955 { }
956};
957
958static const char *
959_ethumb_dbus_get_bytearray(EDBus_Message_Iter *iter)
960{
961 int length;
962 const char *result;
963
964 if (!edbus_message_iter_fixed_array_get(iter, 'y', &result,
965 &length))
966 {
967 ERR("not byte array element. Signature: %s",
968 edbus_message_iter_signature_get(iter));
969 return NULL;
970 }
971
972 if ((length == 0) || (result[0] == '\0'))
973 return NULL;
974 else
975 return eina_stringshare_add_length(result, length);
976}
977
978static void
979_ethumb_dbus_append_bytearray(EDBus_Message_Iter *parent, EDBus_Message_Iter *array, const char *string)
980{
981 int i, size;
982
983 if (!string)
984 string = "";
985
986 size = strlen(string) + 1;
987 for (i = 0; i < size; i++)
988 edbus_message_iter_basic_append(array, 'y', string[i]);
989 edbus_message_iter_container_close(parent, array);
990}
991
992static EDBus_Message *
993_ethumb_dbus_queue_add_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
994{
995 EDBus_Message *reply;
996 const char *file, *key, *thumb, *thumb_key;
997 Ethumbd_Object_Data *odata;
998 Ethumbd_Object *eobject;
999 Ethumbd *ed;
1000 Ethumbd_Request *request;
1001 int id = -1;
1002 EDBus_Message_Iter *file_iter, *key_iter, *thumb_iter, *thumb_key_iter;
1003
1004 if (!edbus_message_arguments_get(msg, "iayayayay", &id, &file_iter,
1005 &key_iter, &thumb_iter, &thumb_key_iter))
1006 {
1007 ERR("Error getting arguments.");
1008 goto end;
1009 }
1010 file = _ethumb_dbus_get_bytearray(file_iter);
1011 key = _ethumb_dbus_get_bytearray(key_iter);
1012 thumb = _ethumb_dbus_get_bytearray(thumb_iter);
1013 thumb_key = _ethumb_dbus_get_bytearray(thumb_key_iter);
1014
1015 if (!file)
1016 {
1017 eina_stringshare_del(key);
1018 eina_stringshare_del(thumb);
1019 eina_stringshare_del(thumb_key);
1020 ERR("no filename given.");
1021 goto end;
1022 }
1023
1024 odata = edbus_service_object_data_get(iface, ODATA);
1025 if (!odata)
1026 {
1027 eina_stringshare_del(file);
1028 eina_stringshare_del(key);
1029 eina_stringshare_del(thumb);
1030 eina_stringshare_del(thumb_key);
1031 ERR("could not get dbus_object data.");
1032 goto end;
1033 }
1034
1035 ed = odata->ed;
1036 eobject = &(ed->queue.table[odata->idx]);
1037 if (!_ethumb_dbus_check_id(eobject, id))
1038 goto end;
1039 request = calloc(1, sizeof(*request));
1040 request->id = id;
1041 request->file = file;
1042 request->key = key;
1043 request->thumb = thumb;
1044 request->thumb_key = thumb_key;
1045 eobject->queue = eina_list_append(eobject->queue, request);
1046 eobject->nqueue++;
1047 ed->queue.nqueue++;
1048 _ethumb_dbus_inc_max_id(eobject, id);
1049
1050 _process_queue_start(ed);
1051
1052end:
1053 reply = edbus_message_method_return_new(msg);
1054 edbus_message_arguments_append(reply, "i", id);
1055 return reply;
1056}
1057
1058static EDBus_Message *
1059_ethumb_dbus_queue_remove_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
1060{
1061 EDBus_Message *reply;
1062 int id;
1063 Ethumbd_Object_Data *odata;
1064 Ethumbd_Object *eobject;
1065 Ethumbd_Request *request;
1066 Ethumbd *ed;
1067 Eina_Bool r = EINA_FALSE;
1068 Eina_List *l;
1069
1070 if (!edbus_message_arguments_get(msg, "i", &id))
1071 {
1072 ERR("Error getting arguments.");
1073 goto end;
1074 }
1075 odata = edbus_service_object_data_get(iface, ODATA);
1076 if (!odata)
1077 {
1078 ERR("could not get dbus_object data.");
1079 goto end;
1080 }
1081
1082 ed = odata->ed;
1083 eobject = &ed->queue.table[odata->idx];
1084 l = eobject->queue;
1085 while (l)
1086 {
1087 request = l->data;
1088 if (id == request->id)
1089 break;
1090 l = l->next;
1091 }
1092
1093 if (l)
1094 {
1095 r = EINA_TRUE;
1096 eina_stringshare_del(request->file);
1097 eina_stringshare_del(request->key);
1098 eina_stringshare_del(request->thumb);
1099 eina_stringshare_del(request->thumb_key);
1100 free(request);
1101 eobject->queue = eina_list_remove_list(eobject->queue, l);
1102 eobject->nqueue--;
1103 ed->queue.nqueue--;
1104 _ethumb_dbus_inc_min_id(eobject);
1105 }
1106
1107 end:
1108 reply = edbus_message_method_return_new(msg);
1109 edbus_message_arguments_append(reply, "b", r);
1110 return reply;
1111}
1112
1113static EDBus_Message *
1114_ethumb_dbus_queue_clear_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
1115{
1116 Ethumbd_Object_Data *odata;
1117 Ethumbd_Object *eobject;
1118 Ethumbd *ed;
1119 Eina_List *l;
1120
1121 odata = edbus_service_object_data_get(iface, ODATA);
1122 if (!odata)
1123 {
1124 ERR("could not get dbus_object data.");
1125 goto end;
1126 }
1127
1128 ed = odata->ed;
1129 eobject = &ed->queue.table[odata->idx];
1130 l = eobject->queue;
1131 while (l)
1132 {
1133 Ethumbd_Request *request = l->data;
1134 eina_stringshare_del(request->file);
1135 eina_stringshare_del(request->key);
1136 eina_stringshare_del(request->thumb);
1137 eina_stringshare_del(request->thumb_key);
1138 free(request);
1139 l = eina_list_remove_list(l, l);
1140 }
1141 ed->queue.nqueue -= eobject->nqueue;
1142 eobject->nqueue = 0;
1143
1144 end:
1145 return edbus_message_method_return_new(msg);
1146}
1147
1148static EDBus_Message *
1149_ethumb_dbus_delete_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
1150{
1151 EDBus_Message *reply;
1152 Ethumbd_Object_Data *odata;
1153 Ethumbd *ed;
1154
1155 reply = edbus_message_method_return_new(msg);
1156
1157 odata = edbus_service_object_data_get(iface, ODATA);
1158 if (!odata)
1159 {
1160 ERR("could not get dbus_object data for del_cb.");
1161 return reply;
1162 }
1163 ed = odata->ed;
1164 _ethumb_table_del(ed, odata->idx);
1165 free(odata);
1166
1167 return reply;
1168}
1169
1170static int
1171_ethumb_dbus_fdo_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1172{
1173 int fdo;
1174
1175 if (!edbus_message_iter_arguments_get(variant, "i", &fdo))
1176 {
1177 ERR("invalid param for fdo_set.");
1178 return 0;
1179 }
1180
1181 DBG("setting fdo to: %d", fdo);
1182 request->setup.flags.fdo = 1;
1183 request->setup.fdo = fdo;
1184
1185 return 1;
1186}
1187
1188static int
1189_ethumb_dbus_size_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1190{
1191 EDBus_Message_Iter *st;
1192 int w, h;
1193
1194 if (!edbus_message_iter_arguments_get(variant, "(ii)", &st))
1195 {
1196 ERR("invalid param for size_set.");
1197 return 0;
1198 }
1199
1200 edbus_message_iter_arguments_get(st, "ii", &w, &h);
1201 DBG("setting size to: %dx%d", w, h);
1202 request->setup.flags.size = 1;
1203 request->setup.tw = w;
1204 request->setup.th = h;
1205
1206 return 1;
1207}
1208
1209static int
1210_ethumb_dbus_format_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1211{
1212 int format;
1213
1214 if (!edbus_message_iter_arguments_get(variant, "i", &format))
1215 {
1216 ERR("invalid param for format_set.");
1217 return 0;
1218 }
1219
1220 DBG("setting format to: %d", format);
1221 request->setup.flags.format = 1;
1222 request->setup.format = format;
1223
1224 return 1;
1225}
1226
1227static int
1228_ethumb_dbus_aspect_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1229{
1230 int aspect;
1231
1232 if (!edbus_message_iter_arguments_get(variant, "i", &aspect))
1233 {
1234 ERR("invalid param for aspect_set.");
1235 return 0;
1236 }
1237
1238 DBG("setting aspect to: %d", aspect);
1239 request->setup.flags.aspect = 1;
1240 request->setup.aspect = aspect;
1241
1242 return 1;
1243}
1244
1245static int
1246_ethumb_dbus_orientation_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1247{
1248 int orientation;
1249
1250 if (!edbus_message_iter_arguments_get(variant, "i", &orientation))
1251 {
1252 ERR("invalid param for orientation_set.");
1253 return 0;
1254 }
1255
1256 DBG("setting orientation to: %d", orientation);
1257 request->setup.flags.orientation = 1;
1258 request->setup.orientation = orientation;
1259
1260 return 1;
1261}
1262
1263static int
1264_ethumb_dbus_crop_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1265{
1266 EDBus_Message_Iter *st;
1267 double x, y;
1268
1269 if (!edbus_message_iter_arguments_get(variant, "(dd)", &st))
1270 {
1271 ERR("invalid param for crop_set.");
1272 return 0;
1273 }
1274
1275 edbus_message_iter_arguments_get(st, "dd", &x, &y);
1276 DBG("setting crop to: %3.2f,%3.2f", x, y);
1277 request->setup.flags.crop = 1;
1278 request->setup.cx = x;
1279 request->setup.cy = y;
1280
1281 return 1;
1282}
1283
1284static int
1285_ethumb_dbus_quality_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1286{
1287 int quality;
1288
1289 if (!edbus_message_iter_arguments_get(variant, "i", &quality))
1290 {
1291 ERR("invalid param for quality_set.");
1292 return 0;
1293 }
1294
1295 DBG("setting quality to: %d", quality);
1296 request->setup.flags.quality = 1;
1297 request->setup.quality = quality;
1298
1299 return 1;
1300}
1301
1302
1303static int
1304_ethumb_dbus_compress_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1305{
1306 int compress;
1307
1308 if (!edbus_message_iter_arguments_get(variant, "i", &compress))
1309 {
1310 ERR("invalid param for compress_set.");
1311 return 0;
1312 }
1313
1314 DBG("setting compress to: %d", compress);
1315 request->setup.flags.compress = 1;
1316 request->setup.compress = compress;
1317
1318 return 1;
1319}
1320
1321static int
1322_ethumb_dbus_frame_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1323{
1324 EDBus_Message_Iter *_struct, *file_iter, *group_iter, *swallow_iter;
1325 const char *file, *group, *swallow;
1326
1327 if (!edbus_message_iter_arguments_get(variant, "(ayayay)", &_struct))
1328 {
1329 ERR("invalid param for frame_set.");
1330 return 0;
1331 }
1332
1333 edbus_message_iter_arguments_get(_struct, "ayayay", &file_iter, &group_iter, &swallow_iter);
1334
1335 file = _ethumb_dbus_get_bytearray(file_iter);
1336 group = _ethumb_dbus_get_bytearray(group_iter);
1337 swallow = _ethumb_dbus_get_bytearray(swallow_iter);
1338 DBG("setting frame to \"%s:%s:%s\"", file, group, swallow);
1339 request->setup.flags.frame = 1;
1340 request->setup.theme_file = file;
1341 request->setup.group = group;
1342 request->setup.swallow = swallow;
1343
1344 return 1;
1345}
1346
1347static int
1348_ethumb_dbus_directory_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1349{
1350 const char *directory;
1351 EDBus_Message_Iter *array;
1352
1353 if (!edbus_message_iter_arguments_get(variant, "ay", &array))
1354 {
1355 ERR("invalid param for dir_path_set.");
1356 return 0;
1357 }
1358
1359 directory = _ethumb_dbus_get_bytearray(array);
1360 DBG("setting directory to: %s", directory);
1361 request->setup.flags.directory = 1;
1362 request->setup.directory = directory;
1363
1364 return 1;
1365}
1366
1367static int
1368_ethumb_dbus_category_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1369{
1370 const char *category;
1371 EDBus_Message_Iter *array;
1372
1373 if (!edbus_message_iter_arguments_get(variant, "ay", &array))
1374 {
1375 ERR("invalid param for category.");
1376 return 0;
1377 }
1378
1379 category = _ethumb_dbus_get_bytearray(array);
1380 DBG("setting category to: %s", category);
1381 request->setup.flags.category = 1;
1382 request->setup.category = category;
1383
1384 return 1;
1385}
1386
1387static int
1388_ethumb_dbus_video_time_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1389{
1390 double video_time;
1391
1392 if (!edbus_message_iter_arguments_get(variant, "d", &video_time))
1393 {
1394 ERR("invalid param for video_time_set.");
1395 return 0;
1396 }
1397
1398 DBG("setting video_time to: %3.2f", video_time);
1399 request->setup.flags.video_time = 1;
1400 request->setup.video_time = video_time;
1401
1402 return 1;
1403}
1404
1405static int
1406_ethumb_dbus_video_start_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1407{
1408 double video_start;
1409
1410 if (!edbus_message_iter_arguments_get(variant, "d", &video_start))
1411 {
1412 ERR("invalid param for video_start_set.");
1413 return 0;
1414 }
1415
1416 DBG("setting video_start to: %3.2f", video_start);
1417 request->setup.flags.video_start = 1;
1418 request->setup.video_start = video_start;
1419
1420 return 1;
1421}
1422
1423static int
1424_ethumb_dbus_video_interval_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1425{
1426 double video_interval;
1427
1428 if (!edbus_message_iter_arguments_get(variant, "d", &video_interval))
1429 {
1430 ERR("invalid param for video_interval_set.");
1431 return 0;
1432 }
1433 DBG("setting video_interval to: %3.2f", video_interval);
1434 request->setup.flags.video_interval = 1;
1435 request->setup.video_interval = video_interval;
1436
1437 return 1;
1438}
1439
1440static int
1441_ethumb_dbus_video_ntimes_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1442{
1443 unsigned int video_ntimes;
1444
1445 if (!edbus_message_iter_arguments_get(variant, "u", &video_ntimes))
1446 {
1447 ERR("invalid param for video_ntimes_set.");
1448 return 0;
1449 }
1450
1451 DBG("setting video_ntimes to: %3.2d", video_ntimes);
1452 request->setup.flags.video_ntimes = 1;
1453 request->setup.video_ntimes = video_ntimes;
1454
1455 return 1;
1456}
1457
1458static int
1459_ethumb_dbus_video_fps_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1460{
1461 unsigned int video_fps;
1462
1463 if (!edbus_message_iter_arguments_get(variant, "u", &video_fps))
1464 {
1465 ERR("invalid param for video_fps_set.");
1466 return 0;
1467 }
1468
1469 DBG("setting video_fps to: %3.2d", video_fps);
1470 request->setup.flags.video_fps = 1;
1471 request->setup.video_fps = video_fps;
1472
1473 return 1;
1474}
1475
1476static int
1477_ethumb_dbus_document_page_set(Ethumbd_Object *eobject EINA_UNUSED, EDBus_Message_Iter *variant, Ethumbd_Request *request)
1478{
1479 unsigned int document_page;
1480
1481 if (!edbus_message_iter_arguments_get(variant, "u", &document_page))
1482 {
1483 ERR("invalid param for document_page_set.");
1484 return 0;
1485 }
1486
1487 DBG("setting document_page to: %d", document_page);
1488 request->setup.flags.document_page = 1;
1489 request->setup.document_page = document_page;
1490
1491 return 1;
1492}
1493
1494static struct
1495{
1496 const char *option;
1497 int (*setup_func)(Ethumbd_Object *eobject, EDBus_Message_Iter *variant, Ethumbd_Request *request);
1498} _option_cbs[] = {
1499 {"fdo", _ethumb_dbus_fdo_set},
1500 {"size", _ethumb_dbus_size_set},
1501 {"format", _ethumb_dbus_format_set},
1502 {"aspect", _ethumb_dbus_aspect_set},
1503 {"orientation", _ethumb_dbus_orientation_set},
1504 {"crop", _ethumb_dbus_crop_set},
1505 {"quality", _ethumb_dbus_quality_set},
1506 {"compress", _ethumb_dbus_compress_set},
1507 {"frame", _ethumb_dbus_frame_set},
1508 {"directory", _ethumb_dbus_directory_set},
1509 {"category", _ethumb_dbus_category_set},
1510 {"video_time", _ethumb_dbus_video_time_set},
1511 {"video_start", _ethumb_dbus_video_start_set},
1512 {"video_interval", _ethumb_dbus_video_interval_set},
1513 {"video_ntimes", _ethumb_dbus_video_ntimes_set},
1514 {"video_fps", _ethumb_dbus_video_fps_set},
1515 {"document_page", _ethumb_dbus_document_page_set},
1516 {NULL, NULL}
1517};
1518
1519static int
1520_ethumb_dbus_ethumb_setup_parse_element(Ethumbd_Object *eobject, EDBus_Message_Iter *data, Ethumbd_Request *request)
1521{
1522 EDBus_Message_Iter *variant;
1523 const char *option;
1524 int i, r;
1525
1526 edbus_message_iter_arguments_get(data, "sv", &option, &variant);
1527
1528 r = 0;
1529 for (i = 0; _option_cbs[i].option; i++)
1530 if (!strcmp(_option_cbs[i].option, option))
1531 {
1532 r = 1;
1533 break;
1534 }
1535
1536 if (!r)
1537 {
1538 ERR("ethumb_setup invalid option: %s", option);
1539 return 0;
1540 }
1541
1542 return _option_cbs[i].setup_func(eobject, variant, request);
1543}
1544
1545static EDBus_Message *
1546_ethumb_dbus_ethumb_setup_cb(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
1547{
1548 EDBus_Message *reply;
1549 Ethumbd_Object_Data *odata;
1550 Ethumbd *ed;
1551 Ethumbd_Object *eobject;
1552 Ethumbd_Request *request;
1553 Eina_Bool r = EINA_FALSE;
1554 EDBus_Message_Iter *array;
1555 EDBus_Message_Iter *data;
1556
1557 if (!edbus_message_arguments_get(msg, "a{sv}", &array))
1558 {
1559 ERR("could not get dbus_object data for setup_cb.");
1560 goto end;
1561 }
1562
1563 odata = edbus_service_object_data_get(iface, ODATA);
1564 if (!odata)
1565 {
1566 ERR("could not get dbus_object data for setup_cb.");
1567 goto end;
1568 }
1569
1570 ed = odata->ed;
1571 eobject = &ed->queue.table[odata->idx];
1572
1573 request = calloc(1, sizeof(*request));
1574 request->id = -1;
1575
1576 r = EINA_TRUE;
1577 while (edbus_message_iter_get_and_next(array, 'r', &data) && r)
1578 {
1579 if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, data, request))
1580 r = EINA_FALSE;
1581 }
1582
1583 eobject->queue = eina_list_append(eobject->queue, request);
1584 eobject->nqueue++;
1585 ed->queue.nqueue++;
1586
1587end:
1588 reply = edbus_message_method_return_new(msg);
1589 edbus_message_arguments_append(reply, "b", r);
1590 return reply;
1591}
1592
1593static void
1594_ethumb_dbus_generated_signal(Ethumbd *ed, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
1595{
1596 EDBus_Message *sig;
1597 EDBus_Service_Interface *iface;
1598 EDBus_Message_Iter *iter, *iter_path, *iter_key;
1599 int id32;
1600
1601 id32 = *id;
1602
1603 iface = ed->queue.table[ed->queue.current].iface;
1604 sig = edbus_service_signal_new(iface, ETHUMB_DBUS_OBJECTS_SIGNAL_GENERATED);
1605
1606 iter = edbus_message_iter_get(sig);
1607 edbus_message_iter_arguments_append(iter, "iay", id32, &iter_path);
1608 _ethumb_dbus_append_bytearray(iter, iter_path, thumb_path);
1609 edbus_message_iter_arguments_append(iter, "ay", &iter_key);
1610 _ethumb_dbus_append_bytearray(iter, iter_key, thumb_key);
1611 edbus_message_iter_arguments_append(iter, "b", success);
1612
1613 edbus_service_signal_send(iface, sig);
1614}
1615
1616static const EDBus_Service_Interface_Desc server_desc = {
1617 _ethumb_dbus_interface, _ethumb_dbus_methods
1618};
1619
1620static void
1621_ethumb_dbus_request_name_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
1622{
1623 EDBus_Service_Interface *iface;
1624 const char *errname, *errmsg;
1625 Ethumbd *ed = data;
1626
1627 if (edbus_message_error_get(msg, &errname, &errmsg))
1628 {
1629 ERR("request name error: %s %s", errname, errmsg);
1630 edbus_connection_unref(ed->conn);
1631 return;
1632 }
1633
1634 iface = edbus_service_interface_register(ed->conn, _ethumb_dbus_path,
1635 &server_desc);
1636 EINA_SAFETY_ON_NULL_RETURN(iface);
1637
1638 edbus_service_object_data_set(iface, DAEMON, ed);
1639
1640 _ethumbd_timeout_start(ed);
1641}
1642
1643static int
1644_ethumb_dbus_setup(Ethumbd *ed)
1645{
1646 edbus_name_request(ed->conn, _ethumb_dbus_bus_name, 0,
1647 _ethumb_dbus_request_name_cb, ed);
1648 return 1;
1649}
1650
1651static void
1652_ethumb_dbus_finish(Ethumbd *ed)
1653{
1654 _process_queue_stop(ed);
1655 _ethumb_table_clear(ed);
1656 edbus_connection_unref(ed->conn);
1657 free(ed->queue.table);
1658 free(ed->queue.list);
1659}
1660
1661static Eina_Bool
1662_ethumbd_slave_spawn(Ethumbd_Slave *slave, Ethumbd *ed)
1663{
1664 char buf[PATH_MAX];
1665
1666 slave->bufcmd = NULL;
1667 slave->scmd = 0;
1668
1669 snprintf(buf, sizeof(buf),
1670 "%s/ethumb_client/utils/"MODULE_ARCH"/ethumbd_slave",
1671 eina_prefix_lib_get(_pfx));
1672
1673 slave->exe = ecore_exe_pipe_run(buf,
1674 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, ed);
1675 if (!slave->exe)
1676 {
1677 ERR("could not create slave.");
1678 return 0;
1679 }
1680
1681 return 1;
1682}
1683
1684int
1685main(int argc, char *argv[])
1686{
1687 Eina_Bool quit_option = 0;
1688 int exit_value = 0;
1689 int arg_idx;
1690 Ethumbd ed;
1691 int child;
1692 double timeout = -1;
1693
1694 memset(&ed, 0, sizeof(ed));
1695 ecore_init();
1696 eina_init();
1697
1698 ethumb_init();
1699
1700 if (_log_domain < 0)
1701 {
1702 _log_domain = eina_log_domain_register("ethumbd", NULL);
1703 if (_log_domain < 0)
1704 {
1705 EINA_LOG_CRIT("could not register log domain 'ethumbd'");
1706 exit_value = -8;
1707 goto finish;
1708 }
1709 }
1710
1711 _pfx = eina_prefix_new(argv[0], ethumb_client_init,
1712 "ETHUMB_CLIENT", "ethumb_client", "checkme",
1713 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
1714 PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
1715 if (!_pfx)
1716 {
1717 ERR("Could not get ethumb_client installation prefix.");
1718 exit_value = -7;
1719 goto finish;
1720 }
1721
1722 ed.data_cb = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
1723 _ethumbd_slave_data_read_cb, &ed);
1724 ed.del_cb = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1725 _ethumbd_slave_del_cb, &ed);
1726
1727 child = _ethumbd_slave_spawn(&ed.slave, &ed);
1728 if (!child)
1729 {
1730 exit_value = -6;
1731 goto finish;
1732 }
1733
1734 if (child == 2)
1735 {
1736 exit_value = 0;
1737 goto finish;
1738 }
1739
1740 if (!edbus_init())
1741 {
1742 ERR("could not init edbus.");
1743 exit_value = -1;
1744 goto finish;
1745 }
1746
1747 Ecore_Getopt_Value values[] = {
1748 ECORE_GETOPT_VALUE_DOUBLE(timeout),
1749 ECORE_GETOPT_VALUE_BOOL(quit_option),
1750 ECORE_GETOPT_VALUE_BOOL(quit_option),
1751 ECORE_GETOPT_VALUE_BOOL(quit_option),
1752 ECORE_GETOPT_VALUE_BOOL(quit_option),
1753 ECORE_GETOPT_VALUE_NONE
1754 };
1755
1756 arg_idx = ecore_getopt_parse(&optdesc, values, argc, argv);
1757 if (arg_idx < 0)
1758 {
1759 ERR("Could not parse arguments.");
1760 exit_value = -2;
1761 goto finish;
1762 }
1763
1764 if (quit_option)
1765 goto finish;
1766
1767 ed.conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
1768 if (!ed.conn)
1769 {
1770 ERR("could not connect to session bus.");
1771 exit_value = -3;
1772 goto finish_edbus;
1773 }
1774
1775 ed.timeout = timeout;
1776
1777 if (!_ethumb_dbus_setup(&ed))
1778 {
1779 edbus_connection_unref(ed.conn);
1780 ERR("could not setup dbus connection.");
1781 exit_value = -5;
1782 goto finish_edbus;
1783 }
1784
1785 ecore_main_loop_begin();
1786 _ethumb_dbus_finish(&ed);
1787
1788 finish_edbus:
1789 if (_log_domain >= 0)
1790 {
1791 eina_log_domain_unregister(_log_domain);
1792 _log_domain = -1;
1793 }
1794
1795 edbus_shutdown();
1796 finish:
1797 if (ed.slave.exe)
1798 ecore_exe_quit(ed.slave.exe);
1799
1800 if (_pfx) eina_prefix_free(_pfx);
1801 ethumb_shutdown();
1802 eina_init();
1803 ecore_shutdown();
1804 return exit_value;
1805}
diff --git a/src/bin/ethumb_client/ethumbd_client.c b/src/bin/ethumb_client/ethumbd_client.c
new file mode 100644
index 0000000000..e81fc2e9a7
--- /dev/null
+++ b/src/bin/ethumb_client/ethumbd_client.c
@@ -0,0 +1,330 @@
1/**
2 * @file
3 *
4 * Copyright (C) 2009 by ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library;
18 * if not, see <http://www.gnu.org/licenses/>.
19 *
20 * @author Rafael Antognolli <antognolli@profusion.mobi>
21 */
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <limits.h>
30
31#include <Eina.h>
32#include <Ecore_Getopt.h>
33#include <Ecore.h>
34#include <Ethumb_Client.h>
35
36const char *aspect_opt[] = { "keep", "ignore", "crop", NULL };
37const char *format_opt[] = { "png", "jpg", "eet", NULL };
38struct frame
39{
40 const char *file;
41 const char *group;
42 const char *swallow;
43};
44
45struct options
46{
47 Eina_Rectangle geometry;
48 unsigned int format, aspect;
49 char *format_str;
50 char *aspect_str;
51 char *directory;
52 char *category;
53 struct frame frame;
54 char *src_path;
55 char *src_key;
56 const char *thumb_path;
57 const char *thumb_key;
58 double video_time;
59 int page;
60};
61
62static unsigned char
63_ethumb_getopt_callback_frame_parse(const Ecore_Getopt *parser EINA_UNUSED, const Ecore_Getopt_Desc *desc EINA_UNUSED, const char *str, void *data EINA_UNUSED, Ecore_Getopt_Value *storage)
64{
65 struct frame *f = (struct frame *)storage->ptrp;
66 const char *tfile, *tgroup, *tswallow, *base, *sep;
67
68 base = str;
69 sep = strchr(base, ':');
70 if (!sep)
71 goto error;
72 tfile = eina_stringshare_add_length(base, sep - base);
73 base = sep + 1;
74
75 sep = strchr(base, ':');
76 if (!sep)
77 {
78 eina_stringshare_del(tfile);
79 goto error;
80 }
81 tgroup = eina_stringshare_add_length(base, sep - base);
82 base = sep + 1;
83 if (base[0] == '\0')
84 {
85 eina_stringshare_del(tfile);
86 eina_stringshare_del(tgroup);
87 goto error;
88 }
89 tswallow = eina_stringshare_add(base);
90
91 f->file = tfile;
92 f->group = tgroup;
93 f->swallow = tswallow;
94 return 1;
95
96 error:
97 fprintf(stderr,
98 "ERROR: invalid theme, not in format "
99 "'file:group:swallow_part': '%s'\n",
100 str);
101 return 0;
102}
103
104const Ecore_Getopt optdesc = {
105 "ethumbd_client",
106 NULL,
107 PACKAGE_VERSION,
108 "(C) 2009 - ProFUSION embedded systems",
109 "LGPL v2.1 - GNU Lesser General Public License",
110 "Thumbnails generator client using DBus and ethumbd.\n"
111 "\n"
112 "This program uses ethumbd server to create thumbnails from pictures. "
113 "It's an example of use and a test for ethumbd.\n",
114 0,
115 {
116 ECORE_GETOPT_CALLBACK_ARGS
117 ('s', "size", "thumbnail size expected.",
118 "WxH", ecore_getopt_callback_size_parse, NULL),
119 ECORE_GETOPT_CHOICE
120 ('f', "format", "file format to save.", format_opt),
121 ECORE_GETOPT_CHOICE
122 ('a', "aspect", "original image aspect ratio.", aspect_opt),
123 ECORE_GETOPT_STORE_STR
124 ('d', "directory", "directory to save thumbnails."),
125 ECORE_GETOPT_STORE_STR
126 ('c', "category", "thumbnails category."),
127 ECORE_GETOPT_CALLBACK_ARGS
128 ('t', "theme", "path to theme file, group and swallow part.",
129 "file:group:swallow_part", _ethumb_getopt_callback_frame_parse, NULL),
130 ECORE_GETOPT_STORE_STR
131 ('k', "key", "key inside eet file to read image from."),
132 ECORE_GETOPT_STORE_DOUBLE
133 ('v', "video_time", "time of video frame to use as thumbnail."),
134 ECORE_GETOPT_STORE_INT
135 ('p', "document_page", "document page to use as thumbnail."),
136 ECORE_GETOPT_LICENSE('L', "license"),
137 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
138 ECORE_GETOPT_VERSION('V', "version"),
139 ECORE_GETOPT_HELP('h', "help"),
140 ECORE_GETOPT_SENTINEL
141 }
142};
143
144static void
145_thumb_report(const char *mode, const char *src_path, const char *src_key, const char *thumb_path, const char *thumb_key)
146{
147 printf("%s '%s' '%s' => '%s' '%s'\n",
148 mode,
149 src_path, src_key ? src_key : "",
150 thumb_path, thumb_key ? thumb_key : "");
151}
152
153static void
154_finished_thumb(void *data EINA_UNUSED, Ethumb_Client *client EINA_UNUSED, int id EINA_UNUSED, const char *src_path, const char *src_key, const char *thumb_path, const char *thumb_key, Eina_Bool success)
155{
156 const char *mode = success ? "GENERATED" : "FAILED";
157 _thumb_report(mode, src_path, src_key, thumb_path, thumb_key);
158 ecore_main_loop_quit();
159}
160
161static void
162_exists(void *data, Ethumb_Client *c, EINA_UNUSED Ethumb_Exists *thread, Eina_Bool exists)
163{
164 struct options *opts = data;
165 const char *thumb_path, *thumb_key;
166 long id;
167
168 if (exists)
169 {
170 ethumb_client_thumb_path_get(c, &thumb_path, &thumb_key);
171 _thumb_report
172 ("EXISTS", opts->src_path, opts->src_key, thumb_path, thumb_key);
173 ecore_main_loop_quit();
174 return;
175 }
176
177 id = ethumb_client_generate(c, _finished_thumb, NULL, NULL);
178 if (id < 0)
179 {
180 fputs("ERROR: could not request thumbnail to be generated.\n", stderr);
181 ecore_main_loop_quit();
182 return;
183 }
184 printf("request id=%ld, file='%s', key='%s'\n",
185 id, opts->src_path, opts->src_key ? opts->src_key : "");
186
187}
188
189static void
190_connected(void *data, Ethumb_Client *c, Eina_Bool success)
191{
192 struct options *opts = data;
193
194 if (!success)
195 {
196 fputs("ERROR: could not connect to DBus server.\n", stderr);
197 ecore_main_loop_quit();
198 return;
199 }
200
201 fputs("connected to DBus server, setup parameters...\n", stdout);
202
203 ethumb_client_format_set(c, opts->format);
204 ethumb_client_aspect_set(c, opts->aspect);
205
206 if (opts->directory) ethumb_client_dir_path_set(c, opts->directory);
207 if (opts->category) ethumb_client_category_set(c, opts->category);
208 if (opts->geometry.w > 0 && opts->geometry.h > 0)
209 ethumb_client_size_set(c, opts->geometry.w, opts->geometry.h);
210 if (opts->frame.file)
211 ethumb_client_frame_set
212 (c, opts->frame.file, opts->frame.group, opts->frame.swallow);
213 if (opts->video_time > 0)
214 ethumb_client_video_time_set(c, opts->video_time);
215 if (opts->page > 0)
216 ethumb_client_document_page_set(c, opts->page);
217
218 if (!ethumb_client_file_set(c, opts->src_path, opts->src_key))
219 {
220 fprintf(stderr, "ERROR: could not set file '%s', key '%s'\n",
221 opts->src_path, opts->src_key ? opts->src_key : "");
222 ecore_main_loop_quit();
223 return;
224 }
225
226 ethumb_client_thumb_path_set(c, opts->thumb_path, opts->thumb_key);
227 ethumb_client_thumb_exists(c, _exists, opts);
228}
229
230int
231main(int argc, char *argv[])
232{
233 Ethumb_Client *c;
234 Eina_Bool quit_option = 0;
235 const char *format_str = NULL, *aspect_str = NULL;
236 struct options opts = {
237 {-1, -1, -1, -1},
238 0, 0,
239 NULL, NULL, NULL, NULL,
240 {NULL, NULL, NULL},
241 NULL, NULL, NULL, NULL,
242 0.0,
243 0
244 };
245 int arg_index;
246 int i, ret = 0;
247
248 ethumb_client_init();
249 ecore_init();
250
251 Ecore_Getopt_Value values[] = {
252 ECORE_GETOPT_VALUE_PTR_CAST(opts.geometry),
253 ECORE_GETOPT_VALUE_PTR_CAST(format_str),
254 ECORE_GETOPT_VALUE_PTR_CAST(aspect_str),
255 ECORE_GETOPT_VALUE_STR(opts.directory),
256 ECORE_GETOPT_VALUE_STR(opts.category),
257 ECORE_GETOPT_VALUE_PTR_CAST(opts.frame),
258 ECORE_GETOPT_VALUE_STR(opts.src_key),
259 ECORE_GETOPT_VALUE_DOUBLE(opts.video_time),
260 ECORE_GETOPT_VALUE_INT(opts.page),
261 ECORE_GETOPT_VALUE_BOOL(quit_option),
262 ECORE_GETOPT_VALUE_BOOL(quit_option),
263 ECORE_GETOPT_VALUE_BOOL(quit_option),
264 ECORE_GETOPT_VALUE_BOOL(quit_option),
265 ECORE_GETOPT_VALUE_NONE
266 };
267
268 arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
269 if ((arg_index < 0) || (arg_index == argc))
270 {
271 if (arg_index < 0)
272 fprintf(stderr, "Could not parse arguments.\n");
273 else
274 fprintf(stderr, "Missing source file to thumbnail.\n");
275
276 ret = 1;
277 goto end;
278 }
279
280 if (quit_option)
281 {
282 ret = 0;
283 goto end;
284 }
285
286 for (i = 0; i < 3; i++)
287 if (format_opt[i] == format_str)
288 {
289 opts.format = i;
290 break;
291 }
292
293 for (i = 0; i < 3; i++)
294 if (aspect_opt[i] == aspect_str)
295 {
296 opts.aspect = i;
297 break;
298 }
299
300 opts.src_path = argv[arg_index++];
301 if (arg_index < argc)
302 {
303 opts.thumb_path = argv[arg_index++];
304 if (arg_index < argc)
305 opts.thumb_key = argv[arg_index];
306 }
307
308 c = ethumb_client_connect(_connected, &opts, NULL);
309 if (!c)
310 {
311 fputs("ERROR: could not connect to server.\n", stderr);
312 ret = 2;
313 goto end;
314 }
315
316 ecore_main_loop_begin();
317 ethumb_client_disconnect(c);
318
319 end:
320 if (opts.frame.file)
321 {
322 eina_stringshare_del(opts.frame.file);
323 eina_stringshare_del(opts.frame.group);
324 eina_stringshare_del(opts.frame.swallow);
325 }
326 ecore_shutdown();
327 ethumb_client_shutdown();
328
329 return ret;
330}
diff --git a/src/bin/ethumb_client/ethumbd_private.h b/src/bin/ethumb_client/ethumbd_private.h
new file mode 100644
index 0000000000..688eaddd6b
--- /dev/null
+++ b/src/bin/ethumb_client/ethumbd_private.h
@@ -0,0 +1,41 @@
1#ifndef __ETHUMBD_PRIVATE_H__
2#define __ETHUMBD_PRIVATE_H__ 1
3
4
5enum Ethumbd_Operations
6{
7 ETHUMBD_OP_NEW,
8 ETHUMBD_OP_GENERATE,
9 ETHUMBD_OP_SETUP,
10 ETHUMBD_OP_DEL
11};
12
13enum Ethubmd_Setup_Option
14{
15 ETHUMBD_FDO,
16 ETHUMBD_SIZE_W,
17 ETHUMBD_SIZE_H,
18 ETHUMBD_FORMAT,
19 ETHUMBD_ASPECT,
20 ETHUMBD_ORIENTATION,
21 ETHUMBD_CROP_X,
22 ETHUMBD_CROP_Y,
23 ETHUMBD_QUALITY,
24 ETHUMBD_COMPRESS,
25 ETHUMBD_DIRECTORY,
26 ETHUMBD_CATEGORY,
27 ETHUMBD_FRAME_FILE,
28 ETHUMBD_FRAME_GROUP,
29 ETHUMBD_FRAME_SWALLOW,
30 ETHUMBD_VIDEO_TIME,
31 ETHUMBD_VIDEO_START,
32 ETHUMBD_VIDEO_INTERVAL,
33 ETHUMBD_VIDEO_NTIMES,
34 ETHUMBD_VIDEO_FPS,
35 ETHUMBD_DOCUMENT_PAGE,
36 ETHUMBD_SETUP_FINISHED
37};
38
39void ethumbd_child_start(int pipein, int pipeout);
40
41#endif
diff --git a/src/bin/ethumb_client/ethumbd_slave.c b/src/bin/ethumb_client/ethumbd_slave.c
new file mode 100644
index 0000000000..b1d319a305
--- /dev/null
+++ b/src/bin/ethumb_client/ethumbd_slave.c
@@ -0,0 +1,770 @@
1/**
2 * @file
3 *
4 * Copyright (C) 2009 by ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library;
18 * if not, see <http://www.gnu.org/licenses/>.
19 *
20 * @author Rafael Antognolli <antognolli@profusion.mobi>
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <stdlib.h>
28#include <unistd.h>
29#include <limits.h>
30#include <string.h>
31#include <errno.h>
32
33#include <Eina.h>
34#include <Ecore.h>
35#include <Ethumb.h>
36
37#include "ethumbd_private.h"
38
39#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
40#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
41#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
42#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
43
44#define NETHUMBS 100
45
46static int _log_domain = -1;
47
48struct _Ethumbd_Child
49{
50 Ecore_Fd_Handler *fd_handler;
51 Ethumb *ethumbt[NETHUMBS];
52};
53
54
55int
56_ec_read_safe(int fd, void *buf, ssize_t size)
57{
58 ssize_t todo;
59 char *p;
60
61 todo = size;
62 p = buf;
63
64 while (todo > 0)
65 {
66 ssize_t r;
67
68 r = read(fd, p, todo);
69 if (r > 0)
70 {
71 todo -= r;
72 p += r;
73 }
74 else if (r == 0)
75 return 0;
76 else
77 {
78 if (errno == EINTR || errno == EAGAIN)
79 continue;
80 else
81 {
82 ERR("could not read from fd %d: %s",
83 fd, strerror(errno));
84 return 0;
85 }
86 }
87 }
88
89 return 1;
90}
91
92int
93_ec_write_safe(int fd, const void *buf, ssize_t size)
94{
95 ssize_t todo;
96 const char *p;
97
98 todo = size;
99 p = buf;
100
101 while (todo > 0)
102 {
103 ssize_t r;
104
105 r = write(fd, p, todo);
106 if (r > 0)
107 {
108 todo -= r;
109 p += r;
110 }
111 else if (r == 0)
112 return 0;
113 else
114 {
115 if (errno == EINTR || errno == EAGAIN)
116 continue;
117 else
118 {
119 ERR("could not write to fd %d: %s", fd, strerror(errno));
120 return 0;
121 }
122 }
123 }
124
125 return 1;
126}
127
128static int
129_ec_pipe_str_read(struct _Ethumbd_Child *ec EINA_UNUSED, char **str)
130{
131 int size;
132 int r;
133 char buf[PATH_MAX];
134
135 r = _ec_read_safe(STDIN_FILENO, &size, sizeof(size));
136 if (!r)
137 {
138 *str = NULL;
139 return 0;
140 }
141
142 if (!size)
143 {
144 *str = NULL;
145 return 1;
146 }
147
148 r = _ec_read_safe(STDIN_FILENO, buf, size);
149 if (!r)
150 {
151 *str = NULL;
152 return 0;
153 }
154
155 *str = strdup(buf);
156 return 1;
157}
158
159static struct _Ethumbd_Child *
160_ec_new(void)
161{
162 struct _Ethumbd_Child *ec = calloc(1, sizeof(*ec));
163
164 return ec;
165}
166
167static void
168_ec_free(struct _Ethumbd_Child *ec)
169{
170 int i;
171
172 if (ec->fd_handler)
173 ecore_main_fd_handler_del(ec->fd_handler);
174
175 for (i = 0; i < NETHUMBS; i++)
176 {
177 if (ec->ethumbt[i])
178 ethumb_free(ec->ethumbt[i]);
179 }
180
181 free(ec);
182}
183
184static int
185_ec_op_new(struct _Ethumbd_Child *ec)
186{
187 int r;
188 int idx;
189
190 r = _ec_read_safe(STDIN_FILENO, &idx, sizeof(idx));
191 if (!r)
192 return 0;
193
194 DBG("ethumbd new(). idx = %d", idx);
195
196 ec->ethumbt[idx] = ethumb_new();
197 return 1;
198}
199
200static int
201_ec_op_del(struct _Ethumbd_Child *ec)
202{
203 int r;
204 int idx;
205
206 r = _ec_read_safe(STDIN_FILENO, &idx, sizeof(idx));
207 if (!r)
208 return 0;
209
210 DBG("ethumbd del(). idx = %d", idx);
211
212 ethumb_free(ec->ethumbt[idx]);
213 ec->ethumbt[idx] = NULL;
214 return 1;
215}
216
217static void
218_ec_op_generated_cb(void *data EINA_UNUSED, Ethumb *e, Eina_Bool success)
219{
220 const char *thumb_path, *thumb_key;
221 int size_path, size_key, size_cmd;
222
223 DBG("thumb generated (%i)!", success);
224 ethumb_thumb_path_get(e, &thumb_path, &thumb_key);
225
226 if (!thumb_path)
227 size_path = 0;
228 else
229 size_path = strlen(thumb_path) + 1;
230
231 if (!thumb_key)
232 size_key = 0;
233 else
234 size_key = strlen(thumb_key) + 1;
235
236 size_cmd = sizeof(success) + sizeof(size_path) + size_path +
237 sizeof(size_key) + size_key;
238
239 _ec_write_safe(STDOUT_FILENO, &size_cmd, sizeof(size_cmd));
240 _ec_write_safe(STDOUT_FILENO, &success, sizeof(success));
241
242 _ec_write_safe(STDOUT_FILENO, &size_path, sizeof(size_path));
243 _ec_write_safe(STDOUT_FILENO, thumb_path, size_path);
244
245 _ec_write_safe(STDOUT_FILENO, &size_key, sizeof(size_key));
246 _ec_write_safe(STDOUT_FILENO, thumb_key, size_key);
247}
248
249static int
250_ec_op_generate(struct _Ethumbd_Child *ec)
251{
252 int idx;
253 char *path, *key, *thumb_path, *thumb_key;
254 int r;
255
256 r = _ec_read_safe(STDIN_FILENO, &idx, sizeof(idx));
257 if (!r)
258 return 0;
259
260 r = _ec_pipe_str_read(ec, &path);
261 if (!r)
262 return 0;
263 r = _ec_pipe_str_read(ec, &key);
264 if (!r)
265 return 0;
266 r = _ec_pipe_str_read(ec, &thumb_path);
267 if (!r)
268 return 0;
269 r = _ec_pipe_str_read(ec, &thumb_key);
270 if (!r)
271 return 0;
272
273 ethumb_file_set(ec->ethumbt[idx], path, key);
274 ethumb_thumb_path_set(ec->ethumbt[idx], thumb_path, thumb_key);
275
276 if (ethumb_exists(ec->ethumbt[idx]))
277 {
278 _ec_op_generated_cb(ec, ec->ethumbt[idx], EINA_TRUE);
279 }
280 else
281 {
282 ethumb_generate(ec->ethumbt[idx], _ec_op_generated_cb, ec, NULL);
283 }
284
285 free(path);
286 free(key);
287 free(thumb_path);
288 free(thumb_key);
289
290 return 1;
291}
292
293static int
294_ec_fdo_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
295{
296 int r;
297 int value;
298
299 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
300 if (!r)
301 return 0;
302 ethumb_thumb_fdo_set(e, value);
303 DBG("fdo = %d", value);
304
305 return 1;
306}
307
308static int
309_ec_size_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
310{
311 int r;
312 int w, h;
313 int type;
314
315 r = _ec_read_safe(STDIN_FILENO, &w, sizeof(w));
316 if (!r)
317 return 0;
318 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
319 if (!r)
320 return 0;
321 r = _ec_read_safe(STDIN_FILENO, &h, sizeof(h));
322 if (!r)
323 return 0;
324 ethumb_thumb_size_set(e, w, h);
325 DBG("size = %dx%d", w, h);
326
327 return 1;
328}
329
330static int
331_ec_format_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
332{
333 int r;
334 int value;
335
336 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
337 if (!r)
338 return 0;
339 ethumb_thumb_format_set(e, value);
340 DBG("format = %d", value);
341
342 return 1;
343}
344
345static int
346_ec_aspect_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
347{
348 int r;
349 int value;
350
351 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
352 if (!r)
353 return 0;
354 ethumb_thumb_aspect_set(e, value);
355 DBG("aspect = %d", value);
356
357 return 1;
358}
359
360static int
361_ec_orientation_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
362{
363 int r;
364 int value;
365
366 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
367 if (!r)
368 return 0;
369 ethumb_thumb_orientation_set(e, value);
370 DBG("orientation = %d", value);
371
372 return 1;
373}
374
375static int
376_ec_crop_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
377{
378 int r;
379 float x, y;
380 int type;
381
382 r = _ec_read_safe(STDIN_FILENO, &x, sizeof(x));
383 if (!r)
384 return 0;
385 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
386 if (!r)
387 return 0;
388 r = _ec_read_safe(STDIN_FILENO, &y, sizeof(y));
389 if (!r)
390 return 0;
391 ethumb_thumb_crop_align_set(e, x, y);
392 DBG("crop = %fx%f", x, y);
393
394 return 1;
395}
396
397static int
398_ec_quality_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
399{
400 int r;
401 int value;
402
403 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
404 if (!r)
405 return 0;
406 ethumb_thumb_quality_set(e, value);
407 DBG("quality = %d", value);
408
409 return 1;
410}
411
412static int
413_ec_compress_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
414{
415 int r;
416 int value;
417
418 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
419 if (!r)
420 return 0;
421 ethumb_thumb_compress_set(e, value);
422 DBG("compress = %d", value);
423
424 return 1;
425}
426
427static int
428_ec_frame_set(struct _Ethumbd_Child *ec, Ethumb *e)
429{
430 int r;
431 int type;
432 char *theme_file, *group, *swallow;
433
434 r = _ec_pipe_str_read(ec, &theme_file);
435 if (!r)
436 return 0;
437 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
438 if (!r)
439 return 0;
440 r = _ec_pipe_str_read(ec, &group);
441 if (!r)
442 return 0;
443 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
444 if (!r)
445 return 0;
446 r = _ec_pipe_str_read(ec, &swallow);
447 if (!r)
448 return 0;
449 DBG("frame = %s:%s:%s", theme_file, group, swallow);
450 ethumb_frame_set(e, theme_file, group, swallow);
451 free(theme_file);
452 free(group);
453 free(swallow);
454
455 return 1;
456}
457
458static int
459_ec_directory_set(struct _Ethumbd_Child *ec, Ethumb *e)
460{
461 int r;
462 char *directory;
463
464 r = _ec_pipe_str_read(ec, &directory);
465 if (!r)
466 return 0;
467 ethumb_thumb_dir_path_set(e, directory);
468 DBG("directory = %s", directory);
469 free(directory);
470
471 return 1;
472}
473
474static int
475_ec_category_set(struct _Ethumbd_Child *ec, Ethumb *e)
476{
477 int r;
478 char *category;
479
480 r = _ec_pipe_str_read(ec, &category);
481 if (!r)
482 return 0;
483 ethumb_thumb_category_set(e, category);
484 DBG("category = %s", category);
485 free(category);
486
487 return 1;
488}
489
490static int
491_ec_video_time_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
492{
493 int r;
494 float value;
495
496 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
497 if (!r)
498 return 0;
499 ethumb_video_time_set(e, value);
500 DBG("video_time = %f", value);
501
502 return 1;
503}
504
505static int
506_ec_video_start_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
507{
508 int r;
509 float value;
510
511 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
512 if (!r)
513 return 0;
514 ethumb_video_start_set(e, value);
515 DBG("video_start = %f", value);
516
517 return 1;
518}
519
520static int
521_ec_video_interval_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
522{
523 int r;
524 float value;
525
526 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
527 if (!r)
528 return 0;
529 ethumb_video_interval_set(e, value);
530 DBG("video_interval = %f", value);
531
532 return 1;
533}
534
535static int
536_ec_video_ntimes_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
537{
538 int r;
539 int value;
540
541 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
542 if (!r)
543 return 0;
544 ethumb_video_ntimes_set(e, value);
545 DBG("video_ntimes = %d", value);
546
547 return 1;
548}
549
550static int
551_ec_video_fps_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
552{
553 int r;
554 int value;
555
556 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
557 if (!r)
558 return 0;
559 ethumb_video_fps_set(e, value);
560 DBG("video_fps = %d", value);
561
562 return 1;
563}
564
565static int
566_ec_document_page_set(struct _Ethumbd_Child *ec EINA_UNUSED, Ethumb *e)
567{
568 int r;
569 int value;
570
571 r = _ec_read_safe(STDIN_FILENO, &value, sizeof(value));
572 if (!r)
573 return 0;
574 ethumb_document_page_set(e, value);
575 DBG("document_page = %d", value);
576
577 return 1;
578}
579
580static void
581_ec_setup_process(struct _Ethumbd_Child *ec, int idx, int type)
582{
583 Ethumb *e;
584
585 e = ec->ethumbt[idx];
586
587 switch (type)
588 {
589 case ETHUMBD_FDO:
590 _ec_fdo_set(ec, e);
591 break;
592 case ETHUMBD_SIZE_W:
593 _ec_size_set(ec, e);
594 break;
595 case ETHUMBD_FORMAT:
596 _ec_format_set(ec, e);
597 break;
598 case ETHUMBD_ASPECT:
599 _ec_aspect_set(ec, e);
600 break;
601 case ETHUMBD_ORIENTATION:
602 _ec_orientation_set(ec, e);
603 break;
604 case ETHUMBD_CROP_X:
605 _ec_crop_set(ec, e);
606 break;
607 case ETHUMBD_QUALITY:
608 _ec_quality_set(ec, e);
609 break;
610 case ETHUMBD_COMPRESS:
611 _ec_compress_set(ec, e);
612 break;
613 case ETHUMBD_FRAME_FILE:
614 _ec_frame_set(ec, e);
615 break;
616 case ETHUMBD_DIRECTORY:
617 _ec_directory_set(ec, e);
618 break;
619 case ETHUMBD_CATEGORY:
620 _ec_category_set(ec, e);
621 break;
622 case ETHUMBD_VIDEO_TIME:
623 _ec_video_time_set(ec, e);
624 break;
625 case ETHUMBD_VIDEO_START:
626 _ec_video_start_set(ec, e);
627 break;
628 case ETHUMBD_VIDEO_INTERVAL:
629 _ec_video_interval_set(ec, e);
630 break;
631 case ETHUMBD_VIDEO_NTIMES:
632 _ec_video_ntimes_set(ec, e);
633 break;
634 case ETHUMBD_VIDEO_FPS:
635 _ec_video_fps_set(ec, e);
636 break;
637 case ETHUMBD_DOCUMENT_PAGE:
638 _ec_document_page_set(ec, e);
639 break;
640 default:
641 ERR("wrong type!");
642 }
643}
644
645static int
646_ec_op_setup(struct _Ethumbd_Child *ec)
647{
648 int r;
649 int idx;
650 int type;
651
652 r = _ec_read_safe(STDIN_FILENO, &idx, sizeof(idx));
653 if (!r)
654 return 0;
655
656 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
657 if (!r)
658 return 0;
659 while (type != ETHUMBD_SETUP_FINISHED)
660 {
661 _ec_setup_process(ec, idx, type);
662 r = _ec_read_safe(STDIN_FILENO, &type, sizeof(type));
663 if (!r)
664 return 0;
665 }
666
667 return 1;
668}
669
670static Eina_Bool
671_ec_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
672{
673 struct _Ethumbd_Child *ec = data;
674 int op_id;
675 int r;
676
677 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
678 {
679 ERR("error on pipein! child exiting...");
680 ec->fd_handler = NULL;
681 ecore_main_loop_quit();
682 return 0;
683 }
684
685 r = _ec_read_safe(STDIN_FILENO, &op_id, sizeof(op_id));
686 if (!r)
687 {
688 DBG("ethumbd exited! child exiting...");
689 ec->fd_handler = NULL;
690 ecore_main_loop_quit();
691 return 0;
692 }
693
694 DBG("received op: %d", op_id);
695
696 switch (op_id)
697 {
698 case ETHUMBD_OP_NEW:
699 r = _ec_op_new(ec);
700 break;
701 case ETHUMBD_OP_GENERATE:
702 r = _ec_op_generate(ec);
703 break;
704 case ETHUMBD_OP_SETUP:
705 r = _ec_op_setup(ec);
706 break;
707 case ETHUMBD_OP_DEL:
708 r = _ec_op_del(ec);
709 break;
710 default:
711 ERR("invalid operation: %d", op_id);
712 r = 0;
713 }
714
715 if (!r)
716 {
717 ERR("ethumbd exited! child exiting...");
718 ec->fd_handler = NULL;
719 ecore_main_loop_quit();
720 }
721
722 return r;
723}
724
725static void
726_ec_setup(struct _Ethumbd_Child *ec)
727{
728 ec->fd_handler = ecore_main_fd_handler_add(
729 STDIN_FILENO, ECORE_FD_READ | ECORE_FD_ERROR,
730 _ec_fd_handler, ec, NULL, NULL);
731}
732
733int
734main(int argc EINA_UNUSED, const char *argv[] EINA_UNUSED)
735{
736 struct _Ethumbd_Child *ec;
737
738 ethumb_init();
739
740 if (_log_domain < 0)
741 {
742 _log_domain = eina_log_domain_register("ethumbd_child", NULL);
743
744 if (_log_domain < 0)
745 {
746 EINA_LOG_CRIT("could not register log domain 'ethumbd_child'");
747 ethumb_shutdown();
748 return 1;
749 }
750 }
751
752 ec = _ec_new();
753
754 _ec_setup(ec);
755
756 DBG("child started!");
757 ecore_main_loop_begin();
758 DBG("child finishing.");
759
760 _ec_free(ec);
761
762 if (_log_domain >= 0)
763 {
764 eina_log_domain_unregister(_log_domain);
765 _log_domain = -1;
766 }
767 ethumb_shutdown();
768
769 return 0;
770}