4 * Copyright 2012-2013 Samsung Electronics Co., Ltd
6 * Licensed under the Flora License, Version 1.1 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://floralicense.org/license/
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
25 #include <glib/gprintf.h>
27 #include <vconf-keys.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <linux/types.h>
31 #include <linux/netlink.h>
34 #include <arpa/inet.h>
35 #include <netinet/in.h>
36 #include <sys/ioctl.h>
40 #include "pt_common.h"
45 #define AVAHI_DAEMON "/usr/sbin/avahi-daemon"
46 #define CUPS_DAEMON "/usr/sbin/cupsd"
48 #define AVAHI_TEMP "/opt/var/run/avahi-daemon/pid"
49 #define CLEAR_JOB_TEMP "rm -rf /opt/var/spool/cups/* /opt/var/run/cups/*;killall cupsd"
51 //#define JOB_IN_PROGRESS "Spooling job, "
52 #define JOB_COMPLETE "Job completed."
53 //#define JOB_PAGE_PRINTED "Printed "
55 pt_info_t *g_pt_info = NULL;
57 static Eina_Bool __pt_parse_job_complete(const char *msg)
59 PRINT_SERVICE_FUNC_ENTER;
60 gboolean ret = EINA_FALSE;
62 if (strstr(msg, JOB_COMPLETE) != NULL) {
66 PRINT_SERVICE_FUNC_LEAVE;
70 static Eina_Bool __pt_create_job_subscription(int jobid)
72 PRINT_SERVICE_FUNC_ENTER;
73 PT_RETV_IF(jobid <= 0 , EINA_FALSE, "Invalid jobid[%d]", jobid);
75 char uri[HTTP_MAX_URI];
76 const char *events[100];
78 Eina_List *cursor = NULL;
79 pt_printing_job_t *printing_job = NULL;
81 EINA_LIST_FOREACH(g_pt_info->printing_thd_list, cursor, printing_job) {
82 if (printing_job->job->id == jobid) {
83 PT_DEBUG("Found printing_job for job[%d]", jobid);
87 PT_RETV_IF(printing_job == NULL || printing_job->job->id <= 0, EINA_FALSE
88 , "No found printing_job for job[%d]", jobid);
91 ipp_t *request, *response;
92 ipp_attribute_t *attr;
94 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
95 request = ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION);
97 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 631, "/printers/%s", g_pt_info->active_printer->name);
98 PT_DEBUG("request print-uri: %s\n", uri);
99 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
101 PT_DEBUG("request requesting-user-name: %s\n", cupsUser());
102 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
106 ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
107 num_events, NULL, events);
108 ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
109 "notify-pull-method", NULL, "ippget");
111 if ((response = cupsDoRequest(http, request, "/")) != NULL) {
112 PT_DEBUG("request ok!");
114 if ((attr = ippFindAttribute(response, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL) {
115 printing_job->job->subscription_id = ippGetInteger(attr,0);
116 printing_job->job->sequence_num = 0;
117 PT_DEBUG("Subscription id[%d]\n", printing_job->job->subscription_id);
120 * If the printer does not return a job-state attribute, it does not
121 * conform to the IPP specification - break out immediately and fail
125 PT_DEBUG("No notify-subscription-id available from job-uri.\n");
132 PRINT_SERVICE_FUNC_LEAVE;
136 static Eina_Bool __pt_parse_page_progress_value(const char *msg, int *page, int *progress)
138 PRINT_SERVICE_FUNC_ENTER;
139 PT_RETV_IF(msg == NULL || page == NULL || progress == NULL, EINA_FALSE, "Invalid argument");
142 ret = sscanf(msg, "Printing page %d, %d%%", page, progress);
143 PT_RETV_IF(ret != 2, EINA_FALSE, "Failed to sscanf page, progress");
144 PT_DEBUG("Parsed page: %d, progress: %d", *page, *progress);
146 PRINT_SERVICE_FUNC_LEAVE;
151 * launch daemon, such as cups and avahi
153 static Eina_Bool __pt_get_cupsd_pid(void *data)
155 PRINT_SERVICE_FUNC_ENTER;
158 char pid_str[9] = {0,};
161 fd = fopen("/opt/var/run/cups/cupsd.pid", "r");
163 ret = fgets(pid_str, 8, fd);
165 PT_DEBUG("ret : %s", ret);
167 PT_DEBUG("CUPS process is %d", pid);
171 g_pt_info->cups_pid = pid;
172 PRINT_SERVICE_FUNC_LEAVE;
173 return ECORE_CALLBACK_CANCEL;
176 static void __pt_launch_daemon(void)
178 PRINT_SERVICE_FUNC_ENTER;
186 cups_argv[0] = "cupsd";
189 avahi_argv[0] = "avahi-daemon";
190 avahi_argv[1] = "-s";
191 avahi_argv[2] = "--no-drop-root";
192 avahi_argv[3] = "--no-chroot";
193 avahi_argv[4] = "--debug";
194 avahi_argv[5] = NULL;
196 pt_utils_remove_files_in("/opt/var/spool/cups");
197 pt_utils_remove_files_in("/opt/var/run/cups");
200 when temp file content is NULL
201 avahi daemon will not start
202 delete this file can avoid this issue
204 if (access(AVAHI_TEMP, F_OK) ==0) {
205 if (unlink(AVAHI_TEMP) != 0) {
206 PT_DEBUG("DEL_AVAHI_TEMP is failed(%d)", errno);
212 PT_DEBUG("I'm avahi process %d", getpid());
213 if (-1 == execv(AVAHI_DAEMON, avahi_argv)) {
214 PT_DEBUG("AVAHI failed");
217 PT_DEBUG("avahi process is %d", pid);
218 g_pt_info->avahi_pid = pid;
222 PT_DEBUG("I'm CUPS process %d", getpid());
223 if (-1 == execv(CUPS_DAEMON, cups_argv)) {
224 PT_DEBUG("exec failed");
227 ecore_timer_add(2.0, (Ecore_Task_Cb)__pt_get_cupsd_pid, NULL);
228 PT_DEBUG("CUPS parent process is %d", pid2);
231 PRINT_SERVICE_FUNC_LEAVE;
234 static gboolean __pt_process_hotplug_event(GIOChannel *source, GIOCondition condition, gpointer data)
236 pt_info_t *info = (pt_info_t *)data;
238 char buf[MAX_MSG_LEN] = {0,};
240 memset(buf, '\0', MAX_MSG_LEN);
241 read_len = recv(info->ueventsocket, buf, sizeof(buf)-1, 0);
243 if (read_len == -1) {
247 if (strstr(buf, "/usb/lp0")) {
249 if (strstr(buf, "add@")) {
250 event = PT_EVENT_USB_PRINTER_ONLINE;
251 } else if (strstr(buf, "remove@")) {
252 event = PT_EVENT_USB_PRINTER_OFFLINE;
254 PT_DEBUG("Unknown usb event!!! So just think offline");
255 event = PT_EVENT_USB_PRINTER_OFFLINE;
258 if (info->evt_cb != NULL) {
259 info->evt_cb(event, info->user_data, NULL);
261 PT_DEBUG("Failed to send hotplug event because of info->evt_cb is NULL");
271 static gboolean __pt_register_hotplug_event(void *data)
273 pt_info_t *info = (pt_info_t *)data;
274 PT_RETV_IF(info == NULL, FALSE, "Invalid argument");
277 int ueventsocket = -1;
278 GIOChannel *gio = NULL;
279 int g_source_id = -1;
281 ueventsocket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
282 PT_RETV_IF(ueventsocket == -1 , FALSE, "create uevent socket failed. errno=%d", errno);
284 struct sockaddr_nl addr;
285 bzero(&addr, sizeof(struct sockaddr_nl));
286 addr.nl_family = AF_NETLINK;
288 addr.nl_pid = getpid();
290 ret = bind(ueventsocket, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));
292 PT_DEBUG("bind uevent socket failed. errno=%d", errno);
297 const int buffersize = 1024;
298 ret = setsockopt(ueventsocket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
300 PT_DEBUG("set uevent socket option failed. errno=%d", errno);
305 info->ueventsocket = ueventsocket;
306 gio = g_io_channel_unix_new(ueventsocket);
307 g_source_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP, (GIOFunc)__pt_process_hotplug_event, info);
308 g_io_channel_unref(gio);
309 PT_DEBUG("Socket is successfully registered to g_main_loop.\n");
314 static void printing_thread_notify_cb(void *data, Ecore_Thread *thread, void *msg_data)
316 PRINT_SERVICE_FUNC_ENTER;
318 PT_DEBUG("Thread is sent msg successfully.");
321 ipp_attribute_t *attr;
322 pt_progress_info_t progress_info = {0,};
323 pt_printing_job_t *printing_job = NULL;
326 printing_job = (pt_printing_job_t *)data;
328 PT_DEBUG("data is NULL.");
329 // FIXME - no need to call evt_cb?
333 if (msg_data != NULL) {
334 response = (ipp_t *)msg_data;
336 PT_DEBUG("msg_data is NULL.");
337 // FIXME - no need to call evt_cb?
341 PT_DEBUG("Received notification of JOB ID %d", printing_job->job->id);
342 progress_info.job_id = printing_job->job->id;
343 printing_job->page_printed = 0;
345 // Get progress value by parsing notify-text
346 if ((attr = ippFindAttribute(response, "notify-text", IPP_TAG_TEXT)) != NULL) {
348 Eina_Bool job_completed;
351 PT_DEBUG("notify-text : %s", ippGetString(attr, 0, NULL));
353 ret = __pt_parse_page_progress_value(ippGetString(attr, 0, NULL),
354 &printing_job->page_printed,
357 if ((progress > 0) && (NULL != g_pt_info->evt_cb)) {
358 progress_info.progress = progress;
359 progress_info.page_printed = printing_job->page_printed;
360 g_pt_info->evt_cb(PT_EVENT_JOB_PROGRESS, g_pt_info->user_data, &progress_info);
363 job_completed = __pt_parse_job_complete(ippGetString(attr, 0, NULL));
364 if (job_completed == EINA_TRUE) {
365 PT_DEBUG("Job completed. Stop timer callback to get notification");
366 printing_job->printing_state = PT_PRINT_END;
367 if (NULL != g_pt_info->evt_cb) {
368 g_pt_info->evt_cb(PT_EVENT_JOB_COMPLETED, g_pt_info->user_data, &progress_info);
373 attr = ippFindNextAttribute(response, "notify-text", IPP_TAG_TEXT);
375 PT_DEBUG("notify-text : %s", ippGetString(attr, 0, NULL));
376 ret = __pt_parse_page_progress_value(ippGetString(attr, 0, NULL),
377 &printing_job->page_printed,
380 if ((progress > 0) && (NULL != g_pt_info->evt_cb)) {
381 progress_info.progress = progress;
382 progress_info.page_printed = printing_job->page_printed;
383 g_pt_info->evt_cb(PT_EVENT_JOB_PROGRESS, g_pt_info->user_data, &progress_info);
386 job_completed = __pt_parse_job_complete(ippGetString(attr, 0, NULL));
387 if (job_completed == EINA_TRUE) {
388 PT_DEBUG("Job completed. Stop timer callback to get notification");
389 printing_job->printing_state = PT_PRINT_END;
390 if (NULL != g_pt_info->evt_cb) {
391 g_pt_info->evt_cb(PT_EVENT_JOB_COMPLETED, g_pt_info->user_data, &progress_info);
397 for (attr = ippFindAttribute(response, "notify-sequence-number", IPP_TAG_INTEGER);
399 attr = ippFindNextAttribute(response, "notify-sequence-number", IPP_TAG_INTEGER))
400 if (ippGetInteger(attr, 0) > printing_job->job->sequence_num) {
401 printing_job->job->sequence_num = ippGetInteger(attr, 0);
407 PRINT_SERVICE_FUNC_LEAVE;
410 static void printing_thread_end_cb(void *data, Ecore_Thread *thread)
412 PRINT_SERVICE_FUNC_ENTER;
413 PT_RET_IF(data == NULL || thread == NULL, "Invalid argument");
414 PT_DEBUG("Thread is completed successfully.");
416 pt_printing_job_t *printing_job = (pt_printing_job_t *)data;
418 Eina_List *printing_thd_list = NULL;
419 pt_printing_job_t *printing_job_item = NULL;
420 EINA_LIST_FOREACH(g_pt_info->printing_thd_list, printing_thd_list, printing_job_item) {
421 PT_RET_IF(printing_job_item->job == NULL, "printing_job_item->job is NULL");
422 if (printing_job_item->job->id == printing_job->job->id) {
423 PT_DEBUG("Found printing_thd_list for job[%d]", printing_job_item->job->id);
428 PT_RET_IF(printing_job == NULL || printing_job->job->id <= 0
429 , "No found printing_job for job[%d]", printing_job->job->id);
431 g_pt_info->printing_thd_list = eina_list_remove_list(g_pt_info->printing_thd_list, printing_thd_list);
433 PT_IF_FREE_MEM(printing_job->job);
434 PT_IF_FREE_MEM(printing_job);
436 if (eina_list_count(g_pt_info->printing_thd_list) == 0) {
437 if (g_pt_info->evt_cb != NULL) {
438 g_pt_info->evt_cb(PT_EVENT_ALL_THREAD_COMPLETED, g_pt_info->user_data, NULL);
442 PRINT_SERVICE_FUNC_LEAVE;
445 static void printing_thread_cancel_cb(void *data, Ecore_Thread *thread)
447 PRINT_SERVICE_FUNC_ENTER;
448 PT_RET_IF(data == NULL || thread == NULL, "Invalid argument");
449 PT_DEBUG("Thread is canceled successfully.");
451 pt_printing_job_t *printing_job = (pt_printing_job_t *)data;
453 Eina_List *printing_thd_list = NULL;
454 pt_printing_job_t *printing_job_item = NULL;
455 EINA_LIST_FOREACH(g_pt_info->printing_thd_list, printing_thd_list, printing_job_item) {
456 PT_RET_IF(printing_job_item->job == NULL, "printing_job_item->job is NULL");
457 if (printing_job_item->job->id == printing_job->job->id) {
458 PT_DEBUG("Found printing_thd_list for job[%d]", printing_job_item->job->id);
462 PT_RET_IF(printing_job == NULL || printing_job->job->id <= 0
463 , "No found printing_job for job[%d]", printing_job->job->id);
465 g_pt_info->printing_thd_list = eina_list_remove_list(g_pt_info->printing_thd_list, printing_thd_list);
467 PT_IF_FREE_MEM(printing_job->job);
468 PT_IF_FREE_MEM(printing_job);
470 if (eina_list_count(g_pt_info->printing_thd_list) == 0) {
471 if (g_pt_info->evt_cb != NULL) {
472 g_pt_info->evt_cb(PT_EVENT_ALL_THREAD_COMPLETED, g_pt_info->user_data, NULL);
476 PRINT_SERVICE_FUNC_LEAVE;
479 static void printing_thread(void *data, Ecore_Thread *thread)
481 PRINT_SERVICE_FUNC_ENTER;
482 pt_printing_job_t *printing_job = (pt_printing_job_t *)data;
483 //int *jobid = (int *)data;
484 char uri[HTTP_MAX_URI] = {0,};
486 ipp_t *request, *response;
487 pt_progress_info_t progress_info = {0,};
489 PT_DEBUG("print_file %s",printing_job->files[0]);
491 /*start printing file*/
492 printing_job->job->id = cupsPrintFiles(g_pt_info->active_printer->name, printing_job->num_files, printing_job->files, NULL,
493 g_pt_info->num_options, g_pt_info->job_options);
495 cups_option_t *option = g_pt_info->job_options;
497 PT_DEBUG("++++++++++++ PRINTING ++++++++++++\n");
498 for (i=0; i < g_pt_info->num_options; i++) {
499 PT_DEBUG("%d. %s=%s", i, option[i].name, option[i].value);
502 PT_RET_IF(printing_job->job->id <= 0, "print file failed, description:%s", cupsLastErrorString());
504 if (NULL != g_pt_info->evt_cb) {
505 progress_info.job_id = printing_job->job->id;
506 g_pt_info->evt_cb(PT_EVENT_JOB_STARTED, g_pt_info->user_data, &progress_info);
509 __pt_create_job_subscription(printing_job->job->id);
510 //__pt_register_job_progress(printing_job);
512 while (printing_job->printing_state == PT_PRINT_IN_PROGRESS || printing_job->printing_state == PT_PRINT_PENDING) {
513 if (printing_job->printing_state == PT_PRINT_IN_PROGRESS) {
514 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
515 request = ippNewRequest(IPP_GET_NOTIFICATIONS);
517 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 631, "/jobs/%d", printing_job->job->id);
518 PT_DEBUG("request job-uri: %s\n", uri);
519 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
521 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
522 "requesting-user-name", NULL, cupsUser());
524 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
525 "notify-subscription-ids", printing_job->job->subscription_id);
526 if (printing_job->job->sequence_num)
527 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
528 "notify-sequence-numbers", printing_job->job->sequence_num + 1);
530 if ((response = cupsDoRequest(http, request, "/")) != NULL) {
531 PT_DEBUG("request ok!");
533 if (ecore_thread_feedback(thread, (const void *)response) == EINA_FALSE) {
534 PT_DEBUG("Failed to send data to main loop");
544 PRINT_SERVICE_FUNC_LEAVE;
548 * This API let the app start the print job on the active printer, if not find active printer, will use default printer
549 * now only support image and txt file,
550 * will support pdf,office,eml,html in the future
551 * @return If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
552 * @param[in] files is the print files path address
553 * @param[in] num is the print files number
555 int pt_start_print(const char **files, int num)
557 PRINT_SERVICE_FUNC_ENTER;
558 PT_RETV_IF(g_pt_info == NULL || g_pt_info->active_printer == NULL
559 , PT_ERR_INVALID_PARAM, "Invalid argument");
561 PT_RETV_IF(files == NULL || num <=0, PT_ERR_INVALID_PARAM
562 , "Params are not valid (num=%d)", num);
564 /* Check that connection is available */
568 pt_save_user_choice();
570 ret = pt_get_connection_status(&conn_type);
571 if (strcasestr(g_pt_info->active_printer->address,"usb://") != NULL) {
572 if ((conn_type&PT_CONNECTION_USB) == 0) {
573 PT_ERROR("USB printer is selected. But, USB is not available.");
574 PRINT_SERVICE_FUNC_LEAVE;
575 return PT_ERR_NOT_USB_ACCESS;
578 if ((conn_type&PT_CONNECTION_WIFI) == 0 &&
579 (conn_type&PT_CONNECTION_WIFI_DIRECT) == 0) {
580 PT_ERROR("Network printer is selected. But, Network is not available.");
581 PRINT_SERVICE_FUNC_LEAVE;
582 return PT_ERR_NOT_NETWORK_ACCESS;
586 /*get print options*/
587 char *instance = NULL; /* Instance name */
588 cups_dest_t *dest = NULL; /* Current destination */
590 if ((instance = strrchr(g_pt_info->active_printer->name, '/')) != NULL) {
594 dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT,
595 g_pt_info->active_printer->name,
597 PT_RETV_IF(dest == NULL, PT_ERR_UNKNOWN, "get options failed");
599 pt_printing_job_t *printing_job = malloc(sizeof(pt_printing_job_t));
600 PT_RETV_IF(printing_job == NULL, PT_ERR_NO_MEMORY, "Failed to allocate memory for printing_job");
602 memset(printing_job, 0, sizeof(pt_printing_job_t));
604 printing_job->job = (pt_job_info_t *)calloc(1, sizeof(pt_job_info_t));
605 if (NULL == printing_job->job) {
606 PT_IF_FREE_MEM(printing_job);
607 PRINT_SERVICE_FUNC_LEAVE;
608 return PT_ERR_NO_MEMORY;
610 memset(printing_job->job, 0, sizeof(pt_job_info_t));
612 printing_job->printing_state = PT_PRINT_IN_PROGRESS;
613 printing_job->files = files;
614 printing_job->num_files = num;
615 printing_job->printing_thd_hdl = ecore_thread_feedback_run(
617 printing_thread_notify_cb,
618 printing_thread_end_cb,
619 printing_thread_cancel_cb,
623 g_pt_info->printing_thd_list = eina_list_append(g_pt_info->printing_thd_list, printing_job);
624 if (eina_error_get()) {
625 PT_DEBUG("Failed to add eina_list for printing_thd_list");
627 if (ecore_thread_cancel(printing_job->printing_thd_hdl) == EINA_FALSE) {
628 PT_DEBUG("Canceling of printing_thd_hdl[%p] is pended", printing_job->printing_thd_hdl);
631 PT_IF_FREE_MEM(printing_job->job);
632 PT_IF_FREE_MEM(printing_job);
633 PRINT_SERVICE_FUNC_LEAVE;
634 return PT_ERR_NO_MEMORY;
637 PRINT_SERVICE_FUNC_LEAVE;
642 * This API let the app cancel the print job by jobid
643 * @return If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
644 * @param[in] jobid the job id
646 int pt_cancel_print(int jobid)
648 PRINT_SERVICE_FUNC_ENTER;
649 PT_RETV_IF(g_pt_info == NULL || g_pt_info->active_printer == NULL
650 , PT_ERR_INVALID_PARAM, "Invalid argument");
651 PT_RETV_IF(jobid <= 0, PT_ERR_INVALID_PARAM, "Invalid argument");
653 Eina_List *cursor = NULL;
654 pt_printing_job_t *printing_job = NULL;
655 EINA_LIST_FOREACH(g_pt_info->printing_thd_list, cursor, printing_job) {
656 if (printing_job->job->id == jobid) {
657 PT_DEBUG("Found printing_thd_list for job[%d]", jobid);
658 printing_job->printing_state = PT_PRINT_CANCEL;
662 PT_RETV_IF(printing_job == NULL || printing_job->job->id <= 0
663 , PT_ERR_INVALID_PARAM, "No found printing_job for job[%d]", jobid);
665 if (printing_job->job_noti_timer != NULL) {
666 ecore_timer_del(printing_job->job_noti_timer);
667 printing_job->job_noti_timer = NULL;
671 /*cancel printing file*/
672 ret = cupsCancelJob(g_pt_info->active_printer->name, jobid);
673 PT_RETV_IF(ret == 0, PT_ERR_UNKNOWN, "cancel job failed, description:%s", cupsLastErrorString());
675 if (ecore_thread_cancel(printing_job->printing_thd_hdl) == EINA_FALSE) {
676 PT_DEBUG("Canceling of printing_thd_hdl[%p] is pended", printing_job->printing_thd_hdl);
679 PRINT_SERVICE_FUNC_LEAVE;
684 * This API let the app initialize the environment(eg.ip address) by type
685 * @return If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
686 * @param[in] type connection type enumerated in pt_connection_type
688 int pt_init(pt_event_cb evt_cb, void *user_data)
690 PRINT_SERVICE_FUNC_ENTER;
691 PT_RETV_IF(g_pt_info != NULL, PT_ERR_NONE, "Initialized before");
692 PT_RETV_IF(evt_cb == NULL, PT_ERR_INVALID_USER_CB, "evt_cb is NULL");
694 g_pt_info = (pt_info_t *)calloc(1, sizeof(pt_info_t));
695 PT_RETV_IF(g_pt_info == NULL, PT_ERR_NO_MEMORY, "Failed to malloc");
697 g_pt_info->evt_cb = evt_cb;
698 g_pt_info->user_data = user_data;
700 __pt_launch_daemon();
702 g_pt_info->active_printer = (pt_printer_mgr_t *)calloc(1, sizeof(pt_printer_mgr_t));
703 PT_RETV_IF(g_pt_info->active_printer == NULL, PT_ERR_NO_MEMORY, "Failed to malloc");
705 g_pt_info->search = (pt_search_data_t *)calloc(1, sizeof(pt_search_data_t));
706 PT_RETV_IF(g_pt_info->search == NULL, PT_ERR_NO_MEMORY, "Failed to malloc");
708 g_pt_info->search->response_data.printerlist = NULL ;
709 g_pt_info->search->is_searching = 0 ;
710 g_pt_info->ueventsocket = -1;
712 __pt_register_hotplug_event(g_pt_info);
714 PRINT_SERVICE_FUNC_LEAVE;
719 * This API let the app finalize the environment
720 * @return If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
724 PRINT_SERVICE_FUNC_ENTER;
727 if (g_pt_info->printing_thd_list) {
728 pt_utils_free_printing_thd_list(g_pt_info->printing_thd_list);
729 g_pt_info->printing_thd_list = NULL;
732 g_pt_info->ueventsocket = -1;
734 g_pt_info->evt_cb = NULL;
735 g_pt_info->user_data = NULL;
737 kill(g_pt_info->cups_pid, SIGTERM);
738 g_pt_info->cups_pid = -1;
739 kill(g_pt_info->avahi_pid, SIGTERM);
740 g_pt_info->avahi_pid = -1;
744 PRINT_SERVICE_FUNC_LEAVE;
749 * This API let the app get the connect status
750 * @return If success, return PT_ERR_CONNECTION_USB_ACCESS or PT_ERR_CONNECTION_WIFI_ACCESS,
751 * else return the other error code as defined in pt_err_t
753 int pt_get_connection_status(int *net_type)
755 PRINT_SERVICE_FUNC_ENTER;
757 int connection_type = 0;
760 ret = vconf_get_int(VCONFKEY_SYSMAN_USB_HOST_STATUS, &status);
761 PT_RETV_IF(ret != 0, PT_ERR_FAIL, "Critical: Get VCONF usb status failed: %d", status);
763 PT_DEBUG("usb status: %d", status);
765 if (status == VCONFKEY_SYSMAN_USB_HOST_CONNECTED) {
766 connection_type |= PT_CONNECTION_USB;
769 ret = vconf_get_int(VCONFKEY_WIFI_STATE, &status);
770 PT_RETV_IF(ret != 0, PT_ERR_FAIL, "Critical: Get VCONF wifi status failed: %d", status);
772 PT_DEBUG("wifi status: %d", status);
774 if (status >= VCONFKEY_WIFI_CONNECTED) {
775 connection_type |= PT_CONNECTION_WIFI;
778 ret = vconf_get_int(VCONFKEY_WIFI_DIRECT_STATE, &status);
779 PT_RETV_IF(ret != 0, PT_ERR_FAIL, "Critical: Get VCONF wifi-direct status failed: %d", status);
781 PT_DEBUG("wifi-direct status: %d", status);
783 if (status >= VCONFKEY_WIFI_DIRECT_CONNECTED) {
784 connection_type |= PT_CONNECTION_WIFI_DIRECT;
787 *net_type = connection_type;
789 PRINT_SERVICE_FUNC_LEAVE;
794 * This API let the app get the job status
795 * @return return job status
798 pt_job_state_e pt_get_current_job_status(int jobid)
800 PRINT_SERVICE_FUNC_ENTER;
801 PT_RETV_IF(g_pt_info == NULL || g_pt_info->active_printer == NULL, PT_JOB_ERROR, "Invalid g_pt_info");
802 PT_RETV_IF(jobid <= 0, PT_JOB_ERROR, "Invalid argument");
805 pt_job_state_e ret = PT_JOB_ERROR;
806 pt_progress_info_t progress_info = {0,};
807 Eina_List *cursor = NULL;
808 pt_printing_job_t *printing_job = NULL;
810 EINA_LIST_FOREACH(g_pt_info->printing_thd_list, cursor, printing_job) {
811 if (printing_job->job->id == jobid) {
812 PT_DEBUG("Found printing_thd_list for job[%d]", jobid);
817 PT_RETV_IF(printing_job == NULL || printing_job->job->id <= 0, PT_JOB_ERROR
818 , "No found printing_job for job[%d]", jobid);
822 cups_job_t *jb = NULL;
823 num_job = cupsGetJobs(&jb, g_pt_info->active_printer->name, 0, CUPS_WHICHJOBS_ALL);
825 PT_DEBUG("print job id is %d, job num is %d", jobid, num_job);
826 for (i = 0; i < num_job; i++) {
827 PT_DEBUG("job id is %d, job state is %d", jb[i].id, jb[i].state);
828 if (jb[i].id == jobid) {
834 if (ret == PT_JOB_COMPLETED) {
835 event = PT_EVENT_JOB_COMPLETED;
836 printing_job->printing_state = PT_PRINT_END;
837 } else if (ret == PT_JOB_ABORTED) {
838 event = PT_EVENT_JOB_ABORTED;
839 printing_job->printing_state = PT_PRINT_ABORT;
840 } else if (ret == PT_JOB_CANCELED) {
841 event = PT_EVENT_JOB_CANCELED;
842 printing_job->printing_state = PT_PRINT_CANCEL;
843 } else if (ret == PT_JOB_STOPPED) {
844 event = PT_EVENT_JOB_STOPPED;
845 printing_job->printing_state = PT_PRINT_STOP;
846 } else if (ret == PT_JOB_PROCESSING) {
847 event = PT_EVENT_JOB_PROCESSING;
848 printing_job->printing_state = PT_PRINT_IN_PROGRESS;
849 } else if (ret == PT_JOB_HELD) {
850 event = PT_EVENT_JOB_HELD;
851 printing_job->printing_state = PT_PRINT_HELD;
852 } else if (ret == PT_JOB_PENDING) {
853 event = PT_EVENT_JOB_PENDING;
854 printing_job->printing_state = PT_PRINT_PENDING;
856 event = PT_EVENT_JOB_ERROR;
859 if (g_pt_info->evt_cb != NULL) {
860 progress_info.job_id = jobid;
861 g_pt_info->evt_cb(event, g_pt_info->user_data, &progress_info);
863 PT_DEBUG("Failed to send job status to application because of g_pt_info->evt_cb is NULL");
866 PRINT_SERVICE_FUNC_LEAVE;
871 * This API check the printer status
872 * @return If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
874 pt_printer_state_e pt_check_printer_status(pt_printer_mgr_t *printer)
876 PRINT_SERVICE_FUNC_ENTER;
877 PT_RETV_IF(g_pt_info->search == NULL || printer == NULL, PT_PRINTER_OFFLINE, "Printer is offline");
879 // TODO: Need to replace new function without using avahi
881 if (g_pt_info->evt_cb != NULL) {
882 g_pt_info->evt_cb(PT_EVENT_PRINTER_ONLINE, g_pt_info->user_data, NULL);
884 PT_DEBUG("Failed to send printer status to application because of g_pt_info->evt_cb is NULL");
887 PRINT_SERVICE_FUNC_LEAVE;
888 return PT_PRINTER_IDLE;
891 //NOTICE : Use this function instead of system() which has security hole.
892 //if envp is NULL, execute execv. otherwise, execute execvp.
893 //Argument array should include NULL as last element
895 int execute_filter(const char *filter, const char *argv[], char *const envp[]){
900 if ( filter == NULL || argv == NULL ){
901 PT_DEBUG("argument is invalid");
908 PT_DEBUG("Failed to fork");
914 if ( execve(filter, argv, envp) < 0 ){
915 PT_DEBUG("Can't execute(%d)",errno);
919 if ( execv(filter, argv) < 0 ){
920 PT_DEBUG("Can't execute(%d)",errno);
927 if (waitpid(pid, &status, 0) == -1) {
929 PT_DEBUG("Errno is not EINTR");
934 PT_DEBUG("Parent process is normally terminated");