6ebdd8f7d3f09ba5f8bce59993dd3e806f446b61
[apps/core/preloaded/print-service.git] / src / pt_printer.c
1 /*
2 *  Printservice
3 *
4 * Copyright 2012  Samsung Electronics Co., Ltd
5
6 * Licensed under the Flora License, Version 1.0 (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
9
10 * http://floralicense.org/license/
11
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.
17 *
18 */
19
20 #define _GNU_SOURCE
21 #include <sys/types.h>
22 #include <app.h>
23 #include <stdbool.h>
24 #include <glib.h>
25
26 #include "pt_debug.h"
27 #include "pt_common.h"
28 #include "pt_ppd.h"
29 #include "pt_printer.h"
30 #include "pt_utils.h"
31
32 #define PREFERENCE_DEFAULT_PRINTER_NAME "mobileprint_default_printer_name"
33 #define PREFERENCE_DEFAULT_PRINTER_ADDRESS "mobileprint_default_printer_address"
34 #define PREFERENCE_DEFAULT_PRINTER_MFG "mobileprint_default_printer_mfg"
35 #define PREFERENCE_DEFAULT_PRINTER_MDL "mobileprint_default_printer_mdl"
36
37 static void g_printer_data_destroy(gconstpointer a)
38 {
39         free((char *)a);
40 }
41
42 static gboolean __printer_compare(gconstpointer a, gconstpointer b)
43 {
44         pt_printer_info_t *printer_a = (pt_printer_info_t *)a;
45         pt_printer_info_t *printer_b = (pt_printer_info_t *)b;
46         PT_RETV_IF(a==NULL || b==NULL, FALSE, "a or b is NULL");
47
48         if (strcmp(printer_a->device_uri, printer_b->device_uri) == 0) {
49                 return TRUE;
50         } else if (!strncmp(printer_a->device_uri, "dnssd:",6) && !strncmp(printer_b->device_uri, "dnssd:",6)) {
51                 if (strcmp(printer_a->device_info, printer_b->device_info) == 0) {
52                         return TRUE;
53                 } else {
54                         return FALSE;
55                 }
56         }
57         return FALSE;
58 }
59
60 static pt_printer_info_t *pt_util_make_printer_info(const char *device_info,
61                 const char *device_make_and_model,
62                 const char *device_uri)
63 {
64         pt_printer_info_t *localdetail = NULL;
65         localdetail = (pt_printer_info_t *)malloc(sizeof(pt_printer_info_t));
66         PT_RETV_IF(localdetail == NULL, NULL, "localdetail is NULL");
67         memset(localdetail, 0, sizeof(pt_printer_info_t));
68
69         char *device_mfg = NULL;
70         char *device_mdl = NULL;
71         char *device_name = NULL;
72         int ret = 0;
73         ret = pt_utils_get_mfg_mdl(device_make_and_model, &device_mfg, &device_mdl);
74         if ( ret != PT_ERR_NONE) {
75                 PT_IF_FREE_MEM(localdetail);
76                 PT_IF_FREE_MEM(device_mfg);
77                 PT_IF_FREE_MEM(device_mdl);
78                 PT_DEBUG("ERROR : %d in pt_utils_get_mfg_mdl", ret);
79                 return NULL;
80         }
81         if (device_mfg == NULL) {
82                 PT_IF_FREE_MEM(localdetail);
83                 PT_IF_FREE_MEM(device_mdl);
84                 PT_DEBUG("device_mfg == NULL");
85                 return NULL;
86         }
87         if (device_mdl == NULL) {
88                 PT_IF_FREE_MEM(localdetail);
89                 PT_IF_FREE_MEM(device_mfg);
90                 PT_DEBUG("device_mdl == NULL");
91                 return NULL;
92         }
93
94         device_name = calloc(1, strlen(device_mfg)+strlen(device_mdl)+2);
95         if (device_name == NULL) {
96                 PT_IF_FREE_MEM(localdetail);
97                 PT_IF_FREE_MEM(device_mfg);
98                 PT_IF_FREE_MEM(device_mdl);
99                 PT_DEBUG("No memory. calloc failed");
100                 return NULL;
101         }
102
103         strncat(device_name,device_mfg,strlen(device_mfg));
104         strncat(device_name," ",1);
105         strncat(device_name,device_mdl,strlen(device_mdl));
106
107         strncpy(localdetail->model_name, device_mdl, sizeof(localdetail->model_name)-1);
108         strncpy(localdetail->manufacturer, device_mfg, sizeof(localdetail->manufacturer)-1);
109         strncpy(localdetail->product_ui_name, device_name, sizeof(localdetail->product_ui_name)-1);
110         __standardization(localdetail->product_ui_name);
111         strncpy(localdetail->device_uri, device_uri, sizeof(localdetail->device_uri)-1);
112         strncpy(localdetail->device_info, device_info, sizeof(localdetail->device_info)-1);
113
114         PT_IF_FREE_MEM(device_mfg);
115         PT_IF_FREE_MEM(device_mdl);
116         PT_IF_FREE_MEM(device_name);
117
118         return localdetail;
119 }
120
121 static void pt_debug_print_device_attr(ipp_attribute_t *attr)
122 {
123         PT_RET_IF(attr == NULL, "Invalid argument");
124         /* CUPS 1.6.1 support new ippGet function
125                 ippGetBoolean
126                 ippGetCollection
127                 ippGetCount
128                 ippGetDate
129                 ippGetGroupTag
130                 ippGetInteger
131                 ippGetName
132                 ippGetOperation
133                 ippGetRange
134                 ippGetRequestId
135                 ippGetResolution
136                 ippGetState
137                 ippGetStatusCode
138                 ippGetString
139                 ippGetValueTag
140                 ippGetVersion
141           */
142         if (ippGetValueTag(attr) == IPP_TAG_TEXT || ippGetValueTag(attr) == IPP_TAG_URI) {
143                 PT_DEBUG("grp=[%d] name=[%s] text=[%s]", ippGetGroupTag(attr), (ippGetName(attr) ==NULL)?"nill":ippGetName(attr), ippGetString(attr, 0, NULL));
144         } else if (ippGetValueTag(attr) == IPP_TAG_INTEGER) {
145                 PT_DEBUG("grp=[%d] name=[%s] int=[%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), ippGetInteger(attr,0));
146         } else if (ippGetValueTag(attr) == IPP_TAG_BOOLEAN) {
147                 PT_DEBUG("grp=[%d] name=[%s] bool=[%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), ippGetBoolean(attr,0));
148         } else if (ippGetValueTag(attr) == IPP_TAG_RESOLUTION) {
149                 int xres = -1;
150                 int yres = -1;
151                 ipp_res_t units = -1;
152                 xres = ippGetResolution(attr, 0, &yres, &units);
153                 PT_DEBUG("grp=[%d] name=[%s] res=[%d,%d, %d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr),
154                                  xres, yres, units);
155         } else if (ippGetValueTag(attr) == IPP_TAG_RANGE) {
156                 int uppper = -1;
157                 int lower = -1;
158                 lower = ippGetRange(attr, 0, &uppper);
159                 PT_DEBUG("grp=[%d] name=[%s] range=[%d,%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), uppper, lower);
160         } else if (ippGetValueTag(attr) == IPP_TAG_EVENT_NOTIFICATION) {
161                 PT_DEBUG("IPP_TAG_EVENT_NOTIFICATION");
162                 PT_DEBUG("grp=[%d] name=[%s] value_tag=[%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), ippGetValueTag(attr));
163         } else if (ippGetValueTag(attr) == IPP_TAG_SUBSCRIPTION) {
164                 PT_DEBUG("grp=[%d] name=[%s] value_tag=[%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), ippGetValueTag(attr));
165         } else {
166                 PT_DEBUG("grp=[%d] name=[%s] value_tag=[%d]", ippGetGroupTag(attr), (ippGetName(attr)==NULL)?"nill":ippGetName(attr), ippGetValueTag(attr));
167         }
168
169 }
170
171 static void pt_util_add_printer_to_hashlist(GHashTable *printer_hashlist, pt_printer_info_t *printer)
172 {
173         PT_RET_IF(printer == NULL, "printer is NULL");
174         PT_RET_IF(printer_hashlist == NULL, "printer_hashlist is NULL");
175
176         pt_printer_info_t *tempdetail = NULL;
177         tempdetail = (pt_printer_info_t *) g_hash_table_lookup(printer_hashlist, printer);
178
179         if (NULL == tempdetail) {
180                 g_hash_table_insert(printer_hashlist, printer, printer);
181                 PT_DEBUG("Added printer_hashlist: %s", printer->device_uri);
182         } else {
183                 if (strstr(tempdetail->device_uri, "_printer.") && strstr(printer->device_uri, "_ipp.")) {
184                         g_hash_table_replace(printer_hashlist, printer, printer);
185                         PT_DEBUG("Replaced printer_hashlist: %s", printer->device_uri);
186                 } else if (strstr(tempdetail->device_uri, "_pdl-datastream.") &&
187                                    (strstr(printer->device_uri, "_printer.") || strstr(printer->device_uri, "_ipp."))) {
188                         g_hash_table_replace(printer_hashlist, printer, printer);
189                         PT_DEBUG("Replaced printer_hashlist: %s", printer->device_uri);
190                 }
191         }
192 }
193
194 static int compare_printer(pt_printer_mgr_t *printer_a, pt_printer_mgr_t *printer_b)
195 {
196         if (printer_a->is_ppd_exist == TRUE && printer_b->is_ppd_exist == FALSE) {
197                 return -1;
198         } else if (printer_a->is_ppd_exist == FALSE && printer_b->is_ppd_exist == TRUE) {
199                 return 1;
200         } else {
201                 if (strcmp(printer_a->name, printer_b->name) != 0) {
202                         return strcmp(printer_a->name, printer_b->name);
203                 }
204                 else {
205                         return strcmp(printer_a->address, printer_b->address);
206                 }
207         }
208 }
209
210 static void pt_util_append_printer(pt_search_data_t *search_data, GHashTable *printer_hashlist)
211 {
212         GHashTableIter iter;
213         gpointer key, value;
214         pt_printer_info_t *printer_temp = NULL;
215         Eina_Compare_Cb cmp_func = (Eina_Compare_Cb)compare_printer;
216
217         g_hash_table_iter_init(&iter, printer_hashlist);
218         while (g_hash_table_iter_next(&iter, &key, &value)) {
219                 printer_temp = (pt_printer_info_t *)malloc(sizeof(pt_printer_info_t));
220                 PT_RET_IF(printer_temp == NULL, "printer_temp is NULL");
221                 memset(printer_temp, 0, sizeof(pt_printer_info_t));
222                 memcpy(printer_temp, value, sizeof(pt_printer_info_t));
223                 search_data->pt_local_list = eina_list_append(search_data->pt_local_list, (pt_printer_info_t *)printer_temp);
224                 if (eina_error_get()) {
225                         PT_DEBUG("Failed to add eina_list for search_data->pt_local_list");
226                 }
227         }
228
229         /* add searched printer */
230         Eina_List *cursor = NULL;
231         pt_printer_info_t *it = NULL;
232         pt_printer_mgr_t *detail = NULL;
233
234         //TODO:: free ( search_data->response_data.printerlist );  -- dwmax
235         search_data->response_data.printerlist = NULL;
236
237         Eina_Bool bfirst = EINA_TRUE;
238         /* add printer to response list */
239         EINA_LIST_FOREACH(search_data->pt_local_list, cursor, it) {
240                 detail = (pt_printer_mgr_t *)malloc(sizeof(pt_printer_mgr_t));
241                 if (detail != NULL) {
242                         memset(detail, 0, sizeof(pt_printer_mgr_t));
243                         detail->copies = 1;
244                         strncpy(detail->name, it->product_ui_name, PT_MAX_LENGTH -1);
245                         strncpy(detail->address, it->device_uri, PT_MAX_LENGTH -1);
246                         strncpy(detail->mdl, it->model_name, PT_MAX_LENGTH -1);
247                         strncpy(detail->mfg, it->manufacturer, PT_MAX_LENGTH -1);
248                         PT_DEBUG("product %s",it->product_ui_name);
249                         PT_DEBUG("url %s",it->device_uri);
250                         PT_DEBUG("mdl %s",it->model_name);
251                         PT_DEBUG("mfg %s",it->manufacturer);
252
253                         if (EINA_TRUE == bfirst) {
254                                 bfirst = EINA_FALSE;
255                         }
256
257                         if (pt_get_printer_ppd(detail) != PT_ERR_NONE) {
258                                 //Unsupported Printer
259                                 detail->is_ppd_exist = FALSE;
260                         } else {
261                                 detail->is_ppd_exist = TRUE;
262                         }
263
264 //                      search_data->response_data.printerlist = eina_list_append(search_data->response_data.printerlist, detail);
265                         search_data->response_data.printerlist = eina_list_sorted_insert(search_data->response_data.printerlist, cmp_func,detail);
266                         if (eina_error_get()) {
267                                 PT_DEBUG("Failed to add eina_list for search_data->response_data.printerlist");
268                         }
269                 }
270         }
271
272 }
273
274 static void searching_thread_notify_cb(void *data, Ecore_Thread *thread, void *msg_data)
275 {
276         PRINT_SERVICE_FUNC_ENTER;
277         PT_RET_IF(data == NULL, "data is NULL");
278         PT_RET_IF(msg_data == NULL, "msg_data is NULL");
279         PT_DEBUG("Thread is sent msg successfully.");
280
281         pt_search_data_t        *search_data    = NULL;
282         ipp_t                   *response               = NULL;
283
284         search_data = (pt_search_data_t *)data;
285         response = (ipp_t *)msg_data;
286
287         PT_RET_IF(search_data->user_cb == NULL, "user_cb is NULL");
288
289         GHashTable *printer_hashlist = g_hash_table_new_full(g_str_hash, __printer_compare, NULL, (GDestroyNotify)g_printer_data_destroy);
290
291         ipp_attribute_t *attr                           = NULL;
292         const char *device_uri                  = NULL; /* device-uri attribute value */
293         const char *device_info                         = NULL; /* device-info value */
294         const char *device_make_and_model       = NULL; /* device-make-and-model value */
295
296         for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) {
297
298                 pt_debug_print_device_attr(attr);
299
300                 if (ippGetGroupTag(attr) == IPP_TAG_ZERO) {
301                         PT_DEBUG("-----------------------------------------");
302                 } else if (ippGetGroupTag(attr) != IPP_TAG_PRINTER) {
303                         continue;
304                 } else if (!strcmp(ippGetName(attr), "device-info") && ippGetValueTag(attr) == IPP_TAG_TEXT) {
305                         device_info = ippGetString(attr, 0, NULL);
306                 } else if (!strcmp(ippGetName(attr), "device-make-and-model") && ippGetValueTag(attr) == IPP_TAG_TEXT) {
307                         device_make_and_model = ippGetString(attr, 0, NULL);
308                 } else if (!strcmp(ippGetName(attr), "device-uri") && ippGetValueTag(attr) == IPP_TAG_URI) {
309                         device_uri = ippGetString(attr, 0, NULL);
310                 } else {
311                         continue;
312                 }
313
314                 if (device_info == NULL || device_make_and_model == NULL
315                                 || device_uri == NULL) {
316                         continue;
317                 } else if (strcasestr(device_uri, "usb://") ||
318                                    strstr(device_uri,"_pdl-datastream.") ||
319                                    strstr(device_uri,"_ipp.") ||
320                                    strstr(device_uri,"_printer.")) {
321                         pt_printer_info_t *localdetail = NULL;
322                         localdetail = pt_util_make_printer_info(device_info, device_make_and_model, device_uri);
323                         pt_util_add_printer_to_hashlist(printer_hashlist, localdetail);
324                 } else {
325                         PT_DEBUG("the device has another scheme such as socket");
326                 }
327
328                 device_info                             = NULL;
329                 device_uri                              = NULL;
330                 device_make_and_model   = NULL;
331
332         }
333
334         pt_util_append_printer(search_data, printer_hashlist);
335         g_hash_table_destroy(printer_hashlist);
336
337         ippDelete(response);
338         search_data->user_cb(&search_data->response_data);
339
340         PRINT_SERVICE_FUNC_LEAVE;
341 }
342
343 static void searching_thread_end_cb(void *data, Ecore_Thread *thread)
344 {
345         PRINT_SERVICE_FUNC_ENTER;
346         g_pt_info->searching_state = PT_SEARCH_END;
347         PT_DEBUG("Thread is completed successfully.");
348         PRINT_SERVICE_FUNC_LEAVE;
349 }
350
351 static void searching_thread_cancel_cb(void *data, Ecore_Thread *thread)
352 {
353         PRINT_SERVICE_FUNC_ENTER;
354         PT_DEBUG("Thread is canceled successfully.");
355         PRINT_SERVICE_FUNC_LEAVE;
356 }
357
358 static void searching_thread(void *data, Ecore_Thread *thread)
359 {
360         PRINT_SERVICE_FUNC_ENTER;
361         PT_RET_IF(data == NULL, "data is NULL");
362         PT_RET_IF(thread == NULL, "thread is NULL");
363
364         http_t *http                            = NULL;
365         ipp_t *request                  = NULL;
366         ipp_t *response                         = NULL;
367         int connection_status           = 0;
368         int ret                                         = -1;
369         char *exclude_schemes[] = {
370                 "http",
371                 "https",
372                 "ipp",
373                 "ipp15",
374                 "ipps",
375                 "lpd",
376                 "smb",
377                 "snmp",
378                 "socket",
379                 NULL,
380                 NULL
381         };
382         int num_schemes = 9;
383
384         http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
385         PT_RET_IF(http == NULL, "unable to connect server");
386
387         request = ippNewRequest(CUPS_GET_DEVICES);
388         PT_RET_IF(request == NULL, "unable to create request");
389
390         ret = pt_get_connection_status(&connection_status);
391
392         if (ret != PT_ERR_NONE) {
393                 ippDelete(request);
394                 PT_DEBUG("unable to get connection status");
395         }
396
397         if ((connection_status & PT_CONNECTION_USB) == 0) {
398                 exclude_schemes[num_schemes++] = "usb";
399         }
400         if ((connection_status & PT_CONNECTION_WIFI) == 0 &&
401                         (connection_status & PT_CONNECTION_WIFI_DIRECT) == 0) {
402                 exclude_schemes[num_schemes++] = "dnssd";
403         }
404
405         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "exclude-schemes",
406                                   num_schemes ,NULL, exclude_schemes);
407         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "timeout",5);
408
409         if ((response = cupsDoRequest(http, request, "/")) != NULL) {
410                 PT_DEBUG("CUPS_GET_DEVICES (%s)",cupsLastErrorString());
411                 if (g_pt_info->searching_state == PT_SEARCH_CANCEL) {
412                         ippDelete(response);
413                         goto canceled;
414                 }
415
416                 if (ecore_thread_feedback(thread, (const void *)response) == EINA_FALSE) {
417                         PT_DEBUG("Failed to send data to main loop");
418                         ippDelete(response);
419                 }
420         } else {
421                 PT_DEBUG("CUPS_GET_DEVICES (%s)", cupsLastErrorString());
422         }
423 canceled:
424         httpClose(http);
425         PRINT_SERVICE_FUNC_LEAVE;
426 }
427
428 static void __pt_get_printers(pt_search_data_t *data)
429 {
430         PRINT_SERVICE_FUNC_ENTER;
431
432         g_pt_info->searching_thd_hdl = ecore_thread_feedback_run(
433                                                                            searching_thread,
434                                                                            searching_thread_notify_cb,
435                                                                            searching_thread_end_cb,
436                                                                            searching_thread_cancel_cb,
437                                                                            data,
438                                                                            EINA_FALSE);
439
440         PRINT_SERVICE_FUNC_LEAVE;
441 }
442
443 static Eina_Bool __pt_check_cups_before_searching(void *data)
444 {
445         PRINT_SERVICE_FUNC_ENTER;
446         Eina_Bool ret = ECORE_CALLBACK_RENEW;
447
448         if (g_pt_info->cups_pid > 0) {
449                 pt_search_data_t *ad = (pt_search_data_t *)data;
450                 __pt_get_printers(ad);
451                 ret = ECORE_CALLBACK_CANCEL;
452         }
453
454         PRINT_SERVICE_FUNC_LEAVE;
455         return ret;
456 }
457
458 /***
459 * '__enable_printer()' - Enable a printer...
460 * I - Server connection
461 * I - Printer to enable
462 * O - 0 on success, 1 on fail
463 ***/
464
465 static int      __enable_printer(http_t *http, char *printer, char *device_uri)
466 {
467         /* IPP Request */
468         ipp_t *request;
469         ipp_t *response;          /* IPP Response */
470         char uri[HTTP_MAX_URI];  /* URI for printer/class */
471
472         /*
473         * Build a CUPS_ADD_PRINTER request, which requires the following
474         * attributes:
475         *
476         *        attributes-charset
477         *        attributes-natural-language
478         *        printer-uri
479         *        printer-state
480         *        printer-is-accepting-jobs
481         */
482
483         //request = ippNewRequest(CUPS_ADD_PRINTER);
484         request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
485
486         //httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s", printer);
487         httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 631, "/printers/%s", printer);
488         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
489
490         if (device_uri[0] == '/') {
491                 snprintf(uri, sizeof(uri), "file://%s", device_uri);
492                 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, uri);
493         } else {
494                 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, device_uri);
495         }
496
497         ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
498
499         ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
500
501         /*
502         * Do the request and get back a response...
503         */
504         if ((response = cupsDoRequest(http, request, "/admin/")) == NULL) {
505                 PT_DEBUG("cupsDoRequest Failed");
506                 return (1);
507         } else if (ippGetStatusCode(response) > IPP_OK_EVENTS_COMPLETE) {
508                 PT_DEBUG("%x greater than IPP_OK_EVENTS_COMPLETE -- Failed", ippGetStatusCode(response));
509                 ippDelete(response);
510                 return (1);
511         } else {
512                 ippDelete(response);
513                 return (0);
514         }
515
516 }
517
518 static int      __set_printer_ppd(http_t *http, char *printer, char *ppd_file)
519 {
520         ipp_t *request = NULL;
521         ipp_t *response = NULL;
522         char uri[HTTP_MAX_URI] = {0,};
523
524         httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s", printer);
525
526         request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
527
528         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
529         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
530
531         if (ppd) {
532                 ppdClose(ppd);
533                 ppd = NULL;
534         }
535
536         if (ppd_file != NULL) {
537                 PT_DEBUG("ppd file is not NULL. %s", ppd_file);
538
539                 response = cupsDoFileRequest(http, request, "/admin/", ppd_file);
540
541                 if (response != NULL) {
542                         ippDelete(response);
543                         ppd = ppdOpenFile(ppd_file);
544                         if (ppd != NULL) {
545                                 pt_parse_options(ppd);
546                         }
547                 } else {
548                         PT_DEBUG("Failed to call cupsDoFileRequest");
549                 }
550         } else {
551                 PT_DEBUG("ppd file is NULL");
552                 ippDelete(request);
553                 return 1;
554         }
555
556         if (cupsLastError() > IPP_OK_CONFLICT) {
557                 PT_DEBUG("The request is failed, detail description: %s\n", cupsLastErrorString());
558                 return 1;
559         } else {
560                 return 0;
561         }
562 }
563
564 /**
565  *      This function let the app register the printer to the server
566  *      @return    If success, return PT_ERR_NONE, else return PT_ERR_FAIL
567  *      @param[in] printer_name the pointer to the printer's name
568  *      @param[in] scheme the pointer to the register's scheme
569  *      @param[in] ip_address the pointer to the printer's address
570  *      @param[in] ppd_file the pointer to the printer's ppd file
571  */
572 static int pt_utils_regist_printer(char *printer_name, char *scheme, char *ip_address, char *ppd_file)
573 {
574         PT_RETV_IF(printer_name == NULL || ip_address == NULL || ppd_file == NULL , 1 , "Invalid argument");
575
576         /* Connection to server */
577         http_t *http = NULL;
578         char device_url[PT_MAX_LENGTH] = {0,};
579
580         snprintf(device_url, MAX_URI_SIZE, "%s://%s", scheme, ip_address);
581
582         http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
583         PT_RETV_IF(http == NULL, 1, "Unable to connect to server");
584
585         if (__enable_printer(http, printer_name, device_url)) {
586                 PT_DEBUG("enable return 1");
587                 return (1);
588         }
589
590         if (__set_printer_ppd(http, printer_name, ppd_file)) {
591                 return (1);
592         }
593
594         if (http) {
595                 httpClose(http);
596         }
597         PT_DEBUG("add printer success");
598         return (0);
599 }
600
601 /**
602  *      This API let the app get the printer list
603  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
604  *      @param[in] callback the pointer to the function which will be excuted after search
605  *      @param[in] userdata the pointer to the user data
606  */
607 int pt_get_printers(get_printers_cb callback, void *userdata)
608 {
609         PRINT_SERVICE_FUNC_ENTER;
610         PT_RETV_IF(g_pt_info == NULL || g_pt_info->search == NULL, PT_ERR_INVALID_PARAM, "Invalid argument");
611         PT_RETV_IF(callback == NULL || userdata == NULL, PT_ERR_INVALID_PARAM, "Invalid argument");
612
613         /*check the current connection*/
614         int status = -1;
615         int connect_type = 0;
616         status = pt_get_connection_status(&connect_type);
617         PT_RETV_IF(status != PT_ERR_NONE, PT_ERR_FAIL, "Vconf access error");
618         PT_RETV_IF(connect_type == 0, PT_ERR_FAIL, "No available connection");
619
620         pt_search_data_t *ad = g_pt_info->search;
621         ad->response_data.userdata = userdata;
622         ad->user_cb = callback;
623
624         PT_RETV_IF(ad->is_searching == 1 , PT_ERR_UNKNOWN, "in searching");
625
626         /*clear previous search result*/
627         if (ad->pt_local_list != NULL) {
628                 pt_utils_free_local_printer_list(ad->pt_local_list);
629                 ad->pt_local_list = NULL;
630         }
631
632         /*clear previous search result*/
633         if (ad->response_data.printerlist != NULL) {
634                 pt_utils_free_search_list(ad->response_data.printerlist);
635                 ad->response_data.printerlist = NULL;
636         }
637
638         g_pt_info->searching_state = PT_SEARCH_IN_PROGRESS;
639         if (g_pt_info->cups_pid > 0) {
640                 __pt_get_printers(ad);
641         } else {
642                 g_pt_info->cups_checking_timer = ecore_timer_add(1.0, (Ecore_Task_Cb)__pt_check_cups_before_searching, ad);
643         }
644
645         PRINT_SERVICE_FUNC_LEAVE;
646         return PT_ERR_NONE;
647 }
648
649 /**
650  *      This API let the app cancel getting the printer list
651  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
652  */
653 int pt_cancel_get_printers()
654 {
655         PRINT_SERVICE_FUNC_ENTER;
656         PT_RETV_IF(g_pt_info == NULL, PT_ERR_INVALID_PARAM, "g_pt_info is NULL");
657         PT_RETV_IF(g_pt_info->search == NULL, PT_ERR_INVALID_PARAM, "g_pt_info->search is NULL");
658         PT_RETV_IF(g_pt_info->searching_thd_hdl == NULL, PT_ERR_INVALID_PARAM, "g_pt_info->searching_thd_hdl is NULL");
659
660         pt_search_data_t *ad = g_pt_info->search;
661
662         if (g_pt_info->cups_checking_timer) {
663                 ecore_timer_del(g_pt_info->cups_checking_timer);
664                 g_pt_info->cups_checking_timer = NULL;
665         }
666
667         if (ecore_thread_cancel(g_pt_info->searching_thd_hdl) == EINA_FALSE) {
668                 PT_DEBUG("Canceling of searching_thd_hdl[%p] is pended", g_pt_info->searching_thd_hdl);
669         }
670
671         g_pt_info->searching_state = PT_SEARCH_CANCEL;
672
673         /*clear the search result*/
674         if (ad->pt_local_list != NULL) {
675                 pt_utils_free_local_printer_list(ad->pt_local_list);
676                 ad->pt_local_list = NULL;
677         }
678
679         /*clear the search result*/
680         if (ad->response_data.printerlist != NULL) {
681                 pt_utils_free_search_list(ad->response_data.printerlist);
682                 ad->response_data.printerlist = NULL;
683         }
684
685         ad->response_data.userdata = NULL;
686         ad->user_cb = NULL;
687
688         PRINT_SERVICE_FUNC_LEAVE;
689         return PT_ERR_NONE;
690 }
691
692 /**
693  *      This API let the app get the current default printer
694  *      allocates memory for printer info structure! Please free after use!
695  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
696  *      @param[out] printer the pointer to the printer object
697  */
698 int pt_get_default_printer(pt_printer_mgr_t **printer)
699 {
700         PRINT_SERVICE_FUNC_ENTER;
701         PT_RETV_IF(printer == NULL || g_pt_info == NULL, PT_ERR_INVALID_PARAM, "Invalid argument");
702         pt_printer_mgr_t *pt = NULL;
703
704         /* check whether if the default printer exists in the preference */
705         bool isexist = 0;
706         int ret = -1;
707         ret = preference_is_existing(PREFERENCE_DEFAULT_PRINTER_NAME, &isexist);
708         PT_RETV_IF(!isexist, PT_ERR_FAIL, "the default printer name isn't exist in preference!");
709
710         ret = preference_is_existing(PREFERENCE_DEFAULT_PRINTER_ADDRESS, &isexist);
711         PT_RETV_IF(!isexist, PT_ERR_FAIL, "the default printer name isn't exist in preference!");
712
713         /* get the printer in the preference */
714         char *name = NULL;
715         ret = preference_get_string(PREFERENCE_DEFAULT_PRINTER_NAME, &name);
716         PT_RETV_IF(ret, PT_ERR_FAIL, "get the default printer name failed, errno: %d!", ret);
717
718         char *address = NULL;
719         ret = preference_get_string(PREFERENCE_DEFAULT_PRINTER_ADDRESS, &address);
720         PT_RETV_IF(ret, PT_ERR_FAIL, "get the default printer name failed, errno: %d!", ret);
721
722         pt = (pt_printer_mgr_t *)calloc(1, sizeof(pt_printer_mgr_t));
723         PT_RETV_IF(pt == NULL, PT_ERR_FAIL, "Failed to calloc pt");
724         memcpy(pt->name, name, PT_MAX_LENGTH);
725         memcpy(pt->address, address, PT_MAX_LENGTH);
726
727         memcpy(g_pt_info->active_printer, pt, sizeof(pt_printer_mgr_t));
728
729         PT_DEBUG("get printer info from preference, name: %s, address: %s!",
730                          pt->name, pt->address);
731
732         PT_IF_FREE_MEM(name);
733         PT_IF_FREE_MEM(address);
734
735         *printer = pt;
736
737         PRINT_SERVICE_FUNC_LEAVE;
738         return PT_ERR_NONE;
739 }
740
741 /**
742  *      This API let the app set a printer as the default printer
743  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
744  *      @param[in] printer the pointer to the printer object
745  */
746 int pt_set_default_printer(pt_printer_mgr_t *printer)
747 {
748         PRINT_SERVICE_FUNC_ENTER;
749         PT_RETV_IF(printer == NULL || g_pt_info == NULL, PT_ERR_INVALID_PARAM, "Invalid argument");
750
751         /*check the current connection*/
752         int status = -1;
753         int connect_type = 0;
754         status = pt_get_connection_status(&connect_type);
755
756         PT_RETV_IF(status != PT_ERR_NONE, PT_ERR_FAIL, "Vconf access error");
757         PT_RETV_IF(connect_type == 0, PT_ERR_FAIL, "No available connection");
758
759         /* set the printer name in the preference */
760         int ret = -1;
761         ret = preference_set_string(PREFERENCE_DEFAULT_PRINTER_NAME, (const char *)printer->name);
762         PT_RETV_IF(ret, PT_ERR_FAIL, "set the default printer name(%s) failed!", printer->name);
763
764         /* set the printer address in the preference */
765         ret = preference_set_string(PREFERENCE_DEFAULT_PRINTER_ADDRESS, (const char *)printer->address);
766         PT_RETV_IF(ret, PT_ERR_FAIL, "set the default printer name(%s) failed!", printer->address);
767
768         /* set the printer address in the preference */
769         ret = preference_set_string(PREFERENCE_DEFAULT_PRINTER_MFG, (const char *)printer->mfg);
770         PT_RETV_IF(ret, PT_ERR_FAIL, "set the default printer name(%s) failed!", printer->mfg);
771
772         /* set the printer address in the preference */
773         ret = preference_set_string(PREFERENCE_DEFAULT_PRINTER_MDL, (const char *)printer->mdl);
774         PT_RETV_IF(ret, PT_ERR_FAIL, "set the default printer name(%s) failed!", printer->mdl);
775
776         PRINT_SERVICE_FUNC_LEAVE;
777         return PT_ERR_NONE;
778 }
779
780 /**
781  *      This API let the app get the current active printer
782  *      allocates memory for printer info structure! Please free after use!
783  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
784  *      @param[out] printer the pointer to the printer object
785  */
786 int pt_get_active_printer(pt_printer_mgr_t **printer)
787 {
788         PRINT_SERVICE_FUNC_ENTER;
789         PT_RETV_IF(g_pt_info == NULL || g_pt_info->active_printer == NULL
790                            , PT_ERR_INVALID_PARAM, "global printer information is NULL or no active printer");
791         PT_RETV_IF(printer == NULL, PT_ERR_INVALID_PARAM, "printer is NULL");
792
793         pt_printer_mgr_t *pt = NULL;
794         pt = (pt_printer_mgr_t *)malloc(sizeof(pt_printer_mgr_t));
795         PT_RETV_IF(pt == NULL, PT_ERR_NO_MEMORY, "Not enough memory");
796
797         memset(pt, 0, sizeof(pt_printer_mgr_t));
798         memcpy(pt, g_pt_info->active_printer, sizeof(pt_printer_mgr_t));
799
800         PT_DEBUG("g_pt_info->active_printer->name %s" , g_pt_info->active_printer->name);
801         PT_DEBUG("g_pt_info->active_printer->actived = %d", g_pt_info->active_printer->actived);
802         PT_DEBUG("g_pt_info->active_printer->ppd%s" , g_pt_info->active_printer->ppd);
803         PT_DEBUG("g_pt_info->active_printer->address %s" , g_pt_info->active_printer->address);
804         PT_DEBUG("g_pt_info->active_printer->mfg %s" , g_pt_info->active_printer->mfg);
805         PT_DEBUG("g_pt_info->active_printer->mdl %s" , g_pt_info->active_printer->mdl);
806
807         *printer = pt;
808
809         PRINT_SERVICE_FUNC_LEAVE;
810         return PT_ERR_NONE;
811 }
812
813
814 /**
815  *      This API let the app select a specify printer as active printer
816  *      @return   If success, return PT_ERR_NONE, else return the other error code as defined in pt_err_t
817  *      @param[in] printer the pointer to the printer object
818  */
819 int pt_set_active_printer(pt_printer_mgr_t *printer)
820 {
821         PRINT_SERVICE_FUNC_ENTER;
822         PT_RETV_IF(g_pt_info == NULL || g_pt_info->active_printer == NULL
823                            , PT_ERR_INVALID_PARAM, "global printer information is NULL or no active printer");
824         PT_RETV_IF(printer == NULL, PT_ERR_INVALID_PARAM, "printer is NULL");
825
826         /*check the current connection*/
827         int status = -1;
828         int connect_type = 0;
829         status = pt_get_connection_status(&connect_type);
830
831         PT_RETV_IF(status != PT_ERR_NONE, PT_ERR_FAIL, "Vconf access error");
832         PT_RETV_IF(connect_type == 0, PT_ERR_FAIL, "No available connection");
833
834         /*register the printer*/
835         int ret = -1;
836
837         if (pt_get_printer_ppd(printer) != PT_ERR_NONE) {
838                 /* Error can not get ppd info*/
839                 PT_DEBUG("Get %s ppd failed", printer->name);
840                 return PT_ERR_INVALID_PARAM;
841         }
842
843         PT_DEBUG("Get ppd info: %s", printer->ppd);
844         PT_DEBUG("address is %s", printer->address);
845
846         if ((strncasecmp(printer->address, "usb://", 6) == 0)) {
847                 /* usb mode */
848                 char *address = printer->address + sizeof("usb://") - 1;
849                 PT_DEBUG("usb address: %s", address);
850
851                 if (address) {
852                         ret = pt_utils_regist_printer(printer->name, "usb", address, printer->ppd);
853                 }
854         } else if ((strncasecmp(printer->address, "dnssd://", 8) == 0)) {
855                 /* dnssd mode */
856                 char *address = printer->address + sizeof("dnssd://") - 1;
857                 PT_DEBUG("dnssd address: %s", address);
858
859                 if (address) {
860                         PT_DEBUG("1. printer structure address: %x", printer);
861                         ret = pt_utils_regist_printer(printer->name, "dnssd", address, printer->ppd);
862                         PT_DEBUG("2. printer structure address: %x", printer);
863                 }
864         } else {
865                 ret = pt_utils_regist_printer(printer->name, "socket", printer->address, printer->ppd);
866         }
867
868         PT_RETV_IF(ret != PT_ERR_NONE, PT_ERR_UNKNOWN, "add printer failed, description:%s", cupsLastErrorString());
869
870         /* only actived printer can print file */
871         printer->actived = 1;
872         memcpy(g_pt_info->active_printer, printer, sizeof(pt_printer_mgr_t));
873         PT_DEBUG("g_pt_info->active_printer->name %s" , g_pt_info->active_printer->name);
874         PT_DEBUG("g_pt_info->active_printer->address %s" , g_pt_info->active_printer->address);
875         PT_DEBUG("g_pt_info->active_printer->mfg %s" , g_pt_info->active_printer->mfg);
876         PT_DEBUG("g_pt_info->active_printer->mdl %s" , g_pt_info->active_printer->mdl);
877
878         PRINT_SERVICE_FUNC_LEAVE;
879         return PT_ERR_NONE;
880 }