Coverage Report

Created: 2026-02-14 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/printing/print_cups.c
Line
Count
Source
1
/*
2
 * Support code for the Common UNIX Printing System ("CUPS")
3
 *
4
 * Copyright 1999-2003 by Michael R Sweet.
5
 * Copyright 2008 Jeremy Allison.
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
/*
22
 * JRA. Converted to utf8 pull/push.
23
 */
24
25
#include "includes.h"
26
#include "printing.h"
27
#include "printing/pcap.h"
28
#include "librpc/gen_ndr/ndr_printcap.h"
29
#include "lib/util/sys_rw.h"
30
#include "lib/util/string_wrappers.h"
31
32
#ifdef HAVE_CUPS
33
#include <cups/cups.h>
34
#include <cups/language.h>
35
#include <cups/http.h>
36
37
/* CUPS prior to version 1.7 doesn't have HTTP_URI_STATUS_OK */
38
#if (CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR < 7)
39
#define HTTP_URI_STATUS_OK HTTP_URI_OK
40
#endif
41
42
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
43
#define HAVE_CUPS_1_6 1
44
#endif
45
46
#ifndef HAVE_CUPS_1_6
47
#define ippGetGroupTag(attr)  attr->group_tag
48
#define ippGetName(attr)      attr->name
49
#define ippGetValueTag(attr)  attr->value_tag
50
#define ippGetStatusCode(ipp) ipp->request.status.status_code
51
#define ippGetInteger(attr, element) attr->values[element].integer
52
#define ippGetString(attr, element, language) attr->values[element].string.text
53
54
static ipp_attribute_t *
55
ippFirstAttribute(ipp_t *ipp)
56
{
57
  if (!ipp)
58
    return (NULL);
59
  return (ipp->current = ipp->attrs);
60
}
61
62
static ipp_attribute_t *
63
ippNextAttribute(ipp_t *ipp)
64
{
65
  if (!ipp || !ipp->current)
66
    return (NULL);
67
  return (ipp->current = ipp->current->next);
68
}
69
70
static int ippSetOperation(ipp_t *ipp, ipp_op_t op)
71
{
72
    ipp->request.op.operation_id = op;
73
    return (1);
74
}
75
76
static int ippSetRequestId(ipp_t *ipp, int request_id)
77
{
78
    ipp->request.any.request_id = request_id;
79
    return (1);
80
}
81
#endif
82
83
static SIG_ATOMIC_T gotalarm;
84
85
/***************************************************************
86
 Signal function to tell us we timed out.
87
****************************************************************/
88
89
static void gotalarm_sig(int signum)
90
0
{
91
0
        gotalarm = 1;
92
0
}
93
94
extern userdom_struct current_user_info;
95
96
/*
97
 * 'cups_passwd_cb()' - The CUPS password callback...
98
 */
99
100
static const char *       /* O - Password or NULL */
101
cups_passwd_cb(const char *prompt)  /* I - Prompt */
102
0
{
103
  /*
104
   * Always return NULL to indicate that no password is available...
105
   */
106
107
0
  return (NULL);
108
0
}
109
110
static http_t *cups_connect(TALLOC_CTX *frame)
111
0
{
112
0
  const struct loadparm_substitution *lp_sub =
113
0
    loadparm_s3_global_substitution();
114
0
  http_t *http = NULL;
115
0
  char *server = NULL, *p = NULL;
116
0
  int port;
117
0
  int timeout = lp_cups_connection_timeout();
118
0
  size_t size;
119
120
0
  if (lp_cups_server(talloc_tos(), lp_sub) != NULL && strlen(lp_cups_server(talloc_tos(), lp_sub)) > 0) {
121
0
    if (!push_utf8_talloc(frame, &server, lp_cups_server(talloc_tos(), lp_sub), &size)) {
122
0
      return NULL;
123
0
    }
124
0
  } else {
125
0
    server = talloc_strdup(frame,cupsServer());
126
0
  }
127
0
  if (!server) {
128
0
    return NULL;
129
0
  }
130
131
0
  p = strchr(server, ':');
132
0
  if (p) {
133
0
    port = atoi(p+1);
134
0
    *p = '\0';
135
0
  } else {
136
0
    port = ippPort();
137
0
  }
138
139
0
  DEBUG(10, ("connecting to cups server %s:%d\n",
140
0
       server, port));
141
142
0
  gotalarm = 0;
143
144
0
  if (timeout) {
145
0
                CatchSignal(SIGALRM, gotalarm_sig);
146
0
                alarm(timeout);
147
0
        }
148
149
0
#if defined(HAVE_HTTPCONNECT2)
150
0
  http = httpConnect2(server,
151
0
          port,
152
0
          NULL,
153
0
          AF_UNSPEC,
154
0
          lp_cups_encrypt() ?
155
0
        HTTP_ENCRYPTION_ALWAYS :
156
0
        HTTP_ENCRYPTION_IF_REQUESTED,
157
0
          1, /* blocking */
158
0
          30 * 1000, /* timeout */
159
0
          NULL);
160
#elif defined(HAVE_HTTPCONNECTENCRYPT)
161
  http = httpConnectEncrypt(server, port, lp_cups_encrypt());
162
#else
163
  http = httpConnect(server, port);
164
#endif
165
166
167
0
  CatchSignal(SIGALRM, SIG_IGN);
168
0
        alarm(0);
169
170
0
  if (http == NULL) {
171
0
    DEBUG(3,("Unable to connect to CUPS server %s:%d - %s\n",
172
0
       server, port, strerror(errno)));
173
0
  }
174
175
0
  return http;
176
0
}
177
178
static bool send_pcap_blob(DATA_BLOB *pcap_blob, int fd)
179
0
{
180
0
  size_t ret;
181
182
0
  ret = sys_write(fd, &pcap_blob->length, sizeof(pcap_blob->length));
183
0
  if (ret != sizeof(pcap_blob->length)) {
184
0
    return false;
185
0
  }
186
187
0
  ret = sys_write(fd, pcap_blob->data, pcap_blob->length);
188
0
  if (ret != pcap_blob->length) {
189
0
    return false;
190
0
  }
191
192
0
  DEBUG(10, ("successfully sent blob of len %d\n", (int)ret));
193
0
  return true;
194
0
}
195
196
static bool recv_pcap_blob(TALLOC_CTX *mem_ctx, int fd, DATA_BLOB *pcap_blob)
197
0
{
198
0
  size_t blob_len;
199
0
  size_t ret;
200
201
0
  ret = sys_read(fd, &blob_len, sizeof(blob_len));
202
0
  if (ret != sizeof(blob_len)) {
203
0
    return false;
204
0
  }
205
206
0
  *pcap_blob = data_blob_talloc_named(mem_ctx, NULL, blob_len,
207
0
             "cups pcap");
208
0
  if (pcap_blob->length != blob_len) {
209
0
    return false;
210
0
  }
211
0
  ret = sys_read(fd, pcap_blob->data, blob_len);
212
0
  if (ret != blob_len) {
213
0
    talloc_free(pcap_blob->data);
214
0
    return false;
215
0
  }
216
217
0
  DEBUG(10, ("successfully recvd blob of len %d\n", (int)ret));
218
0
  return true;
219
0
}
220
221
static bool process_cups_printers_response(TALLOC_CTX *mem_ctx,
222
             ipp_t *response,
223
             struct pcap_data *pcap_data)
224
0
{
225
0
  ipp_attribute_t *attr;
226
0
  char *name;
227
0
  char *info;
228
0
  char *location = NULL;
229
0
  struct pcap_printer *printer;
230
0
  bool ret_ok = false;
231
232
0
  for (attr = ippFirstAttribute(response); attr != NULL;) {
233
         /*
234
    * Skip leading attributes until we hit a printer...
235
    */
236
237
0
    while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_PRINTER)
238
0
      attr = ippNextAttribute(response);
239
240
0
    if (attr == NULL)
241
0
      break;
242
243
         /*
244
    * Pull the needed attributes from this printer...
245
    */
246
247
0
    name       = NULL;
248
0
    info       = NULL;
249
250
0
    while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_PRINTER) {
251
0
      size_t size;
252
0
      if (strcmp(ippGetName(attr), "printer-name") == 0 &&
253
0
          ippGetValueTag(attr) == IPP_TAG_NAME) {
254
0
        if (!pull_utf8_talloc(mem_ctx,
255
0
            &name,
256
0
            ippGetString(attr, 0, NULL),
257
0
            &size)) {
258
0
          goto err_out;
259
0
        }
260
0
      }
261
262
0
      if (strcmp(ippGetName(attr), "printer-info") == 0 &&
263
0
          ippGetValueTag(attr) == IPP_TAG_TEXT) {
264
0
        if (!pull_utf8_talloc(mem_ctx,
265
0
            &info,
266
0
            ippGetString(attr, 0, NULL),
267
0
            &size)) {
268
0
          goto err_out;
269
0
        }
270
0
      }
271
272
0
      if (strcmp(ippGetName(attr), "printer-location") == 0 &&
273
0
          ippGetValueTag(attr) == IPP_TAG_TEXT) {
274
0
        if (!pull_utf8_talloc(mem_ctx,
275
0
            &location,
276
0
            ippGetString(attr, 0, NULL),
277
0
            &size)) {
278
0
          goto err_out;
279
0
        }
280
0
      }
281
282
0
      attr = ippNextAttribute(response);
283
0
    }
284
285
         /*
286
    * See if we have everything needed...
287
    */
288
289
0
    if (name == NULL)
290
0
      break;
291
292
0
    if (pcap_data->count == 0) {
293
0
      printer = talloc_array(mem_ctx, struct pcap_printer, 1);
294
0
    } else {
295
0
      printer = talloc_realloc(mem_ctx, pcap_data->printers,
296
0
             struct pcap_printer,
297
0
             pcap_data->count + 1);
298
0
    }
299
0
    if (printer == NULL) {
300
0
      goto err_out;
301
0
    }
302
0
    pcap_data->printers = printer;
303
0
    pcap_data->printers[pcap_data->count].name = name;
304
0
    pcap_data->printers[pcap_data->count].info = info;
305
0
    pcap_data->printers[pcap_data->count].location = location;
306
0
    pcap_data->count++;
307
0
  }
308
309
0
  ret_ok = true;
310
0
err_out:
311
0
  return ret_ok;
312
0
}
313
314
/*
315
 * request printer list from cups, send result back to up parent via fd.
316
 * returns true if the (possibly failed) result was successfully sent to parent.
317
 */
318
static bool cups_cache_reload_async(int fd)
319
0
{
320
0
  TALLOC_CTX *frame = talloc_stackframe();
321
0
  struct pcap_data pcap_data;
322
0
  http_t    *http = NULL;   /* HTTP connection to server */
323
0
  ipp_t   *request = NULL, /* IPP Request */
324
0
      *response = NULL; /* IPP Response */
325
0
  cups_lang_t *language = NULL; /* Default language */
326
0
  static const char *requested[] =/* Requested attributes */
327
0
      {
328
0
        "printer-name",
329
0
        "printer-info",
330
0
        "printer-location"
331
0
      };
332
0
  bool ret = False;
333
0
  enum ndr_err_code ndr_ret;
334
0
  DATA_BLOB pcap_blob;
335
336
0
  ZERO_STRUCT(pcap_data);
337
0
  pcap_data.status = NT_STATUS_UNSUCCESSFUL;
338
339
0
  DEBUG(5, ("reloading cups printcap cache\n"));
340
341
       /*
342
        * Make sure we don't ask for passwords...
343
  */
344
345
0
        cupsSetPasswordCB(cups_passwd_cb);
346
347
0
  if ((http = cups_connect(frame)) == NULL) {
348
0
    goto out;
349
0
  }
350
351
       /*
352
  * Build a CUPS_GET_PRINTERS request, which requires the following
353
  * attributes:
354
  *
355
  *    attributes-charset
356
  *    attributes-natural-language
357
  *    requested-attributes
358
  */
359
360
0
  request = ippNew();
361
362
0
  ippSetOperation(request, CUPS_GET_PRINTERS);
363
0
  ippSetRequestId(request, 1);
364
365
0
  language = cupsLangDefault();
366
367
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
368
0
                     "attributes-charset", NULL, "utf-8");
369
370
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
371
0
                     "attributes-natural-language", NULL, language->language);
372
373
0
        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
374
0
                "requested-attributes",
375
0
          (sizeof(requested) / sizeof(requested[0])),
376
0
          NULL, requested);
377
378
0
  if ((response = cupsDoRequest(http, request, "/")) == NULL) {
379
0
    DEBUG(0,("Unable to get printer list - %s\n",
380
0
       ippErrorString(cupsLastError())));
381
0
    goto out;
382
0
  }
383
384
0
  ret = process_cups_printers_response(frame, response, &pcap_data);
385
0
  if (!ret) {
386
0
    DEBUG(0,("failed to process cups response\n"));
387
0
    goto out;
388
0
  }
389
390
0
  ippDelete(response);
391
0
  response = NULL;
392
393
       /*
394
  * Build a CUPS_GET_CLASSES request, which requires the following
395
  * attributes:
396
  *
397
  *    attributes-charset
398
  *    attributes-natural-language
399
  *    requested-attributes
400
  */
401
402
0
  request = ippNew();
403
404
0
  ippSetOperation(request, CUPS_GET_CLASSES);
405
0
  ippSetRequestId(request, 1);
406
407
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
408
0
                     "attributes-charset", NULL, "utf-8");
409
410
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
411
0
                     "attributes-natural-language", NULL, language->language);
412
413
0
        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
414
0
                "requested-attributes",
415
0
          (sizeof(requested) / sizeof(requested[0])),
416
0
          NULL, requested);
417
418
0
  if ((response = cupsDoRequest(http, request, "/")) == NULL) {
419
0
    DEBUG(0,("Unable to get printer list - %s\n",
420
0
       ippErrorString(cupsLastError())));
421
0
    goto out;
422
0
  }
423
424
0
  ret = process_cups_printers_response(frame, response, &pcap_data);
425
0
  if (!ret) {
426
0
    DEBUG(0,("failed to process cups response\n"));
427
0
    goto out;
428
0
  }
429
430
0
  pcap_data.status = NT_STATUS_OK;
431
0
 out:
432
0
  if (response)
433
0
    ippDelete(response);
434
435
0
  if (language)
436
0
    cupsLangFree(language);
437
438
0
  if (http)
439
0
    httpClose(http);
440
441
0
  ret = false;
442
0
  ndr_ret = ndr_push_struct_blob(&pcap_blob, frame, &pcap_data,
443
0
               (ndr_push_flags_fn_t)ndr_push_pcap_data);
444
0
  if (ndr_ret == NDR_ERR_SUCCESS) {
445
0
    ret = send_pcap_blob(&pcap_blob, fd);
446
0
  }
447
448
0
  TALLOC_FREE(frame);
449
0
  return ret;
450
0
}
451
452
static struct tevent_fd *cache_fd_event;
453
454
static bool cups_pcap_load_async(struct tevent_context *ev,
455
         struct messaging_context *msg_ctx,
456
         int *pfd)
457
0
{
458
0
  int fds[2];
459
0
  pid_t pid;
460
0
  NTSTATUS status;
461
462
0
  *pfd = -1;
463
464
0
  if (cache_fd_event) {
465
0
    DEBUG(3,("cups_pcap_load_async: already waiting for "
466
0
      "a refresh event\n" ));
467
0
    return false;
468
0
  }
469
470
0
  DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
471
472
0
  if (pipe(fds) == -1) {
473
0
    return false;
474
0
  }
475
476
0
  pid = fork();
477
0
  if (pid == (pid_t)-1) {
478
0
    DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
479
0
      strerror(errno) ));
480
0
    close(fds[0]);
481
0
    close(fds[1]);
482
0
    return false;
483
0
  }
484
485
0
  if (pid) {
486
0
    DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
487
0
      (unsigned int)pid ));
488
    /* Parent. */
489
0
    close(fds[1]);
490
0
    *pfd = fds[0];
491
0
    return true;
492
0
  }
493
494
  /* Child. */
495
496
0
  close_all_print_db();
497
498
0
  status = reinit_after_fork(msg_ctx, ev, true);
499
0
  if (!NT_STATUS_IS_OK(status)) {
500
0
    DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
501
0
    smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
502
0
  }
503
504
0
  close(fds[0]);
505
0
  cups_cache_reload_async(fds[1]);
506
0
  close(fds[1]);
507
0
  TALLOC_FREE(msg_ctx);
508
0
  _exit(0);
509
0
}
510
511
struct cups_async_cb_args {
512
  int pipe_fd;
513
  struct tevent_context *event_ctx;
514
  struct messaging_context *msg_ctx;
515
  void (*post_cache_fill_fn)(struct tevent_context *,
516
           struct messaging_context *);
517
};
518
519
static void cups_async_callback(struct tevent_context *event_ctx,
520
        struct tevent_fd *event,
521
        uint16_t flags,
522
        void *p)
523
0
{
524
0
  TALLOC_CTX *frame = talloc_stackframe();
525
0
  struct cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
526
0
  struct pcap_cache *tmp_pcap_cache = NULL;
527
0
  bool ret_ok;
528
0
  struct pcap_data pcap_data;
529
0
  DATA_BLOB pcap_blob;
530
0
  enum ndr_err_code ndr_ret;
531
0
  uint32_t i;
532
533
0
  DEBUG(5,("cups_async_callback: callback received for printer data. "
534
0
    "fd = %d\n", cb_args->pipe_fd));
535
536
0
  ret_ok = recv_pcap_blob(frame, cb_args->pipe_fd, &pcap_blob);
537
0
  if (!ret_ok) {
538
0
    DEBUG(0,("failed to recv pcap blob\n"));
539
0
    goto err_out;
540
0
  }
541
542
0
  ndr_ret = ndr_pull_struct_blob(&pcap_blob, frame, &pcap_data,
543
0
               (ndr_pull_flags_fn_t)ndr_pull_pcap_data);
544
0
  if (ndr_ret != NDR_ERR_SUCCESS) {
545
0
    goto err_out;
546
0
  }
547
548
0
  if (!NT_STATUS_IS_OK(pcap_data.status)) {
549
0
    DEBUG(3,("failed to retrieve printer list: %s\n",
550
0
       nt_errstr(pcap_data.status)));
551
0
    goto err_out;
552
0
  }
553
554
0
  for (i = 0; i < pcap_data.count; i++) {
555
0
    ret_ok = pcap_cache_add_specific(&tmp_pcap_cache,
556
0
             pcap_data.printers[i].name,
557
0
             pcap_data.printers[i].info,
558
0
             pcap_data.printers[i].location);
559
0
    if (!ret_ok) {
560
0
      DEBUG(0, ("failed to add to tmp pcap cache\n"));
561
0
      goto err_out;
562
0
    }
563
0
  }
564
565
  /* replace the system-wide pcap cache with a (possibly empty) new one */
566
0
  ret_ok = pcap_cache_replace(tmp_pcap_cache);
567
0
  if (!ret_ok) {
568
0
    DEBUG(0, ("failed to replace pcap cache\n"));
569
0
  } else if (cb_args->post_cache_fill_fn != NULL) {
570
    /* Caller requested post cache fill callback */
571
0
    cb_args->post_cache_fill_fn(cb_args->event_ctx,
572
0
              cb_args->msg_ctx);
573
0
  }
574
0
err_out:
575
0
  pcap_cache_destroy_specific(&tmp_pcap_cache);
576
0
  TALLOC_FREE(frame);
577
0
  TALLOC_FREE(cache_fd_event);
578
0
  close(cb_args->pipe_fd);
579
0
  TALLOC_FREE(cb_args);
580
0
}
581
582
bool cups_cache_reload(struct tevent_context *ev,
583
           struct messaging_context *msg_ctx,
584
           void (*post_cache_fill_fn)(struct tevent_context *,
585
              struct messaging_context *))
586
0
{
587
0
  struct cups_async_cb_args *cb_args;
588
0
  int *p_pipe_fd;
589
590
0
  cb_args = talloc(NULL, struct cups_async_cb_args);
591
0
  if (cb_args == NULL) {
592
0
    return false;
593
0
  }
594
595
0
  cb_args->post_cache_fill_fn = post_cache_fill_fn;
596
0
  cb_args->event_ctx = ev;
597
0
  cb_args->msg_ctx = msg_ctx;
598
0
  p_pipe_fd = &cb_args->pipe_fd;
599
0
  *p_pipe_fd = -1;
600
601
  /* Set up an async refresh. */
602
0
  if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
603
0
    talloc_free(cb_args);
604
0
    return false;
605
0
  }
606
607
0
  DEBUG(10,("cups_cache_reload: async read on fd %d\n",
608
0
    *p_pipe_fd ));
609
610
  /* Trigger an event when the pipe can be read. */
611
0
  cache_fd_event = tevent_add_fd(ev,
612
0
        NULL, *p_pipe_fd,
613
0
        TEVENT_FD_READ,
614
0
        cups_async_callback,
615
0
        (void *)cb_args);
616
0
  if (!cache_fd_event) {
617
0
    close(*p_pipe_fd);
618
0
    TALLOC_FREE(cb_args);
619
0
    return false;
620
0
  }
621
622
0
  return true;
623
0
}
624
625
/*
626
 * 'cups_job_delete()' - Delete a job.
627
 */
628
629
static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
630
0
{
631
0
  TALLOC_CTX *frame = talloc_stackframe();
632
0
  int   ret = 1;    /* Return value */
633
0
  http_t    *http = NULL;   /* HTTP connection to server */
634
0
  ipp_t   *request = NULL, /* IPP Request */
635
0
      *response = NULL; /* IPP Response */
636
0
  cups_lang_t *language = NULL; /* Default language */
637
0
  char *user = NULL;
638
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
639
0
  http_uri_status_t ustatus;
640
0
  size_t size;
641
642
0
  DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
643
644
       /*
645
        * Make sure we don't ask for passwords...
646
  */
647
648
0
        cupsSetPasswordCB(cups_passwd_cb);
649
650
       /*
651
  * Try to connect to the server...
652
  */
653
654
0
  if ((http = cups_connect(frame)) == NULL) {
655
0
    goto out;
656
0
  }
657
658
       /*
659
  * Build an IPP_CANCEL_JOB request, which requires the following
660
  * attributes:
661
  *
662
  *    attributes-charset
663
  *    attributes-natural-language
664
  *    job-uri
665
  *    requesting-user-name
666
  */
667
668
0
  request = ippNew();
669
670
0
  ippSetOperation(request, IPP_CANCEL_JOB);
671
0
  ippSetRequestId(request, 1);
672
673
0
  language = cupsLangDefault();
674
675
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
676
0
                     "attributes-charset", NULL, "utf-8");
677
678
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
679
0
               "attributes-natural-language", NULL, language->language);
680
681
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
682
0
           uri,
683
0
           sizeof(uri),
684
0
           "ipp",
685
0
           NULL, /* username */
686
0
           "localhost",
687
0
           ippPort(),
688
0
           "/jobs/%d",
689
0
           pjob->sysjob);
690
0
  if (ustatus != HTTP_URI_STATUS_OK) {
691
0
    goto out;
692
0
  }
693
694
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
695
696
0
  if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
697
0
    goto out;
698
0
  }
699
700
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
701
0
               NULL, user);
702
703
       /*
704
  * Do the request and get back a response...
705
  */
706
707
0
  if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
708
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
709
0
      DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
710
0
        ippErrorString(cupsLastError())));
711
0
    } else {
712
0
      ret = 0;
713
0
    }
714
0
  } else {
715
0
    DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
716
0
      ippErrorString(cupsLastError())));
717
0
  }
718
719
0
 out:
720
0
  if (response)
721
0
    ippDelete(response);
722
723
0
  if (language)
724
0
    cupsLangFree(language);
725
726
0
  if (http)
727
0
    httpClose(http);
728
729
0
  TALLOC_FREE(frame);
730
0
  return ret;
731
0
}
732
733
734
/*
735
 * 'cups_job_pause()' - Pause a job.
736
 */
737
738
static int cups_job_pause(int snum, struct printjob *pjob)
739
0
{
740
0
  TALLOC_CTX *frame = talloc_stackframe();
741
0
  int   ret = 1;    /* Return value */
742
0
  http_t    *http = NULL;   /* HTTP connection to server */
743
0
  ipp_t   *request = NULL, /* IPP Request */
744
0
      *response = NULL; /* IPP Response */
745
0
  cups_lang_t *language = NULL; /* Default language */
746
0
  char *user = NULL;
747
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
748
0
  http_uri_status_t ustatus;
749
0
  size_t size;
750
751
0
  DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
752
753
       /*
754
        * Make sure we don't ask for passwords...
755
  */
756
757
0
        cupsSetPasswordCB(cups_passwd_cb);
758
759
       /*
760
  * Try to connect to the server...
761
  */
762
763
0
  if ((http = cups_connect(frame)) == NULL) {
764
0
    goto out;
765
0
  }
766
767
       /*
768
  * Build an IPP_HOLD_JOB request, which requires the following
769
  * attributes:
770
  *
771
  *    attributes-charset
772
  *    attributes-natural-language
773
  *    job-uri
774
  *    requesting-user-name
775
  */
776
777
0
  request = ippNew();
778
779
0
  ippSetOperation(request, IPP_HOLD_JOB);
780
0
  ippSetRequestId(request, 1);
781
782
0
  language = cupsLangDefault();
783
784
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
785
0
                     "attributes-charset", NULL, "utf-8");
786
787
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
788
0
               "attributes-natural-language", NULL, language->language);
789
790
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
791
0
           uri,
792
0
           sizeof(uri),
793
0
           "ipp",
794
0
           NULL, /* username */
795
0
           "localhost",
796
0
           ippPort(),
797
0
           "/jobs/%d",
798
0
           pjob->sysjob);
799
0
  if (ustatus != HTTP_URI_STATUS_OK) {
800
0
    goto out;
801
0
  }
802
803
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
804
805
0
  if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
806
0
    goto out;
807
0
  }
808
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
809
0
               NULL, user);
810
811
       /*
812
  * Do the request and get back a response...
813
  */
814
815
0
  if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
816
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
817
0
      DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
818
0
        ippErrorString(cupsLastError())));
819
0
    } else {
820
0
      ret = 0;
821
0
    }
822
0
  } else {
823
0
    DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
824
0
      ippErrorString(cupsLastError())));
825
0
  }
826
827
0
 out:
828
0
  if (response)
829
0
    ippDelete(response);
830
831
0
  if (language)
832
0
    cupsLangFree(language);
833
834
0
  if (http)
835
0
    httpClose(http);
836
837
0
  TALLOC_FREE(frame);
838
0
  return ret;
839
0
}
840
841
842
/*
843
 * 'cups_job_resume()' - Resume a paused job.
844
 */
845
846
static int cups_job_resume(int snum, struct printjob *pjob)
847
0
{
848
0
  TALLOC_CTX *frame = talloc_stackframe();
849
0
  int   ret = 1;    /* Return value */
850
0
  http_t    *http = NULL;   /* HTTP connection to server */
851
0
  ipp_t   *request = NULL, /* IPP Request */
852
0
      *response = NULL; /* IPP Response */
853
0
  cups_lang_t *language = NULL; /* Default language */
854
0
  char *user = NULL;
855
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
856
0
  http_uri_status_t ustatus;
857
0
  size_t size;
858
859
0
  DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
860
861
       /*
862
        * Make sure we don't ask for passwords...
863
  */
864
865
0
        cupsSetPasswordCB(cups_passwd_cb);
866
867
       /*
868
  * Try to connect to the server...
869
  */
870
871
0
  if ((http = cups_connect(frame)) == NULL) {
872
0
    goto out;
873
0
  }
874
875
       /*
876
  * Build an IPP_RELEASE_JOB request, which requires the following
877
  * attributes:
878
  *
879
  *    attributes-charset
880
  *    attributes-natural-language
881
  *    job-uri
882
  *    requesting-user-name
883
  */
884
885
0
  request = ippNew();
886
887
0
  ippSetOperation(request, IPP_RELEASE_JOB);
888
0
  ippSetRequestId(request, 1);
889
890
0
  language = cupsLangDefault();
891
892
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
893
0
                     "attributes-charset", NULL, "utf-8");
894
895
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
896
0
               "attributes-natural-language", NULL, language->language);
897
898
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
899
0
           uri,
900
0
           sizeof(uri),
901
0
           "ipp",
902
0
           NULL, /* username */
903
0
           "localhost",
904
0
           ippPort(),
905
0
           "/jobs/%d",
906
0
           pjob->sysjob);
907
0
  if (ustatus != HTTP_URI_STATUS_OK) {
908
0
    goto out;
909
0
  }
910
911
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
912
913
0
  if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
914
0
    goto out;
915
0
  }
916
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
917
0
               NULL, user);
918
919
       /*
920
  * Do the request and get back a response...
921
  */
922
923
0
  if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
924
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
925
0
      DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
926
0
        ippErrorString(cupsLastError())));
927
0
    } else {
928
0
      ret = 0;
929
0
    }
930
0
  } else {
931
0
    DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
932
0
      ippErrorString(cupsLastError())));
933
0
  }
934
935
0
 out:
936
0
  if (response)
937
0
    ippDelete(response);
938
939
0
  if (language)
940
0
    cupsLangFree(language);
941
942
0
  if (http)
943
0
    httpClose(http);
944
945
0
  TALLOC_FREE(frame);
946
0
  return ret;
947
0
}
948
949
950
/*
951
 * 'cups_job_submit()' - Submit a job for printing.
952
 */
953
954
static int cups_job_submit(int snum, struct printjob *pjob,
955
         enum printing_types printing_type,
956
         char *lpq_cmd)
957
0
{
958
0
  TALLOC_CTX *frame = talloc_stackframe();
959
0
  const struct loadparm_substitution *lp_sub =
960
0
    loadparm_s3_global_substitution();
961
0
  int   ret = 1;    /* Return value */
962
0
  http_t    *http = NULL;   /* HTTP connection to server */
963
0
  ipp_t   *request = NULL, /* IPP Request */
964
0
      *response = NULL; /* IPP Response */
965
0
  ipp_attribute_t *attr_job_id = NULL; /* IPP Attribute "job-id" */
966
0
  cups_lang_t *language = NULL; /* Default language */
967
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
968
0
  http_uri_status_t ustatus;
969
0
  char *new_jobname = NULL;
970
0
  int   num_options = 0;
971
0
  cups_option_t   *options = NULL;
972
0
  char *printername = NULL;
973
0
  char *user = NULL;
974
0
  char *jobname = NULL;
975
0
  char *cupsoptions = NULL;
976
0
  char *filename = NULL;
977
0
  size_t size;
978
979
0
  DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
980
981
       /*
982
        * Make sure we don't ask for passwords...
983
  */
984
985
0
        cupsSetPasswordCB(cups_passwd_cb);
986
987
       /*
988
  * Try to connect to the server...
989
  */
990
991
0
  if ((http = cups_connect(frame)) == NULL) {
992
0
    goto out;
993
0
  }
994
995
       /*
996
  * Build an IPP_PRINT_JOB request, which requires the following
997
  * attributes:
998
  *
999
  *    attributes-charset
1000
  *    attributes-natural-language
1001
  *    printer-uri
1002
  *    requesting-user-name
1003
  *    [document-data]
1004
  */
1005
1006
0
  request = ippNew();
1007
1008
0
  ippSetOperation(request, IPP_PRINT_JOB);
1009
0
  ippSetRequestId(request, 1);
1010
1011
0
  language = cupsLangDefault();
1012
1013
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1014
0
                     "attributes-charset", NULL, "utf-8");
1015
1016
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1017
0
               "attributes-natural-language", NULL, language->language);
1018
1019
0
  if (!push_utf8_talloc(frame, &printername,
1020
0
            lp_printername(talloc_tos(), lp_sub, snum),
1021
0
            &size)) {
1022
0
    goto out;
1023
0
  }
1024
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1025
0
           uri,
1026
0
           sizeof(uri),
1027
0
           "ipp",
1028
0
           NULL, /* username */
1029
0
           "localhost",
1030
0
           ippPort(),
1031
0
           "/printers/%s",
1032
0
           printername);
1033
0
  if (ustatus != HTTP_URI_STATUS_OK) {
1034
0
    goto out;
1035
0
  }
1036
1037
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1038
0
               "printer-uri", NULL, uri);
1039
1040
0
  if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
1041
0
    goto out;
1042
0
  }
1043
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1044
0
               NULL, user);
1045
1046
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1047
0
               "job-originating-host-name", NULL,
1048
0
         pjob->clientmachine);
1049
1050
0
  if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
1051
0
    goto out;
1052
0
  }
1053
0
  new_jobname = talloc_asprintf(frame,
1054
0
      "%s%.8u %s", PRINT_SPOOL_PREFIX,
1055
0
      pjob->jobid, jobname);
1056
0
  if (new_jobname == NULL) {
1057
0
    goto out;
1058
0
  }
1059
1060
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1061
0
               new_jobname);
1062
1063
  /*
1064
   * add any options defined in smb.conf
1065
   */
1066
1067
0
  if (!push_utf8_talloc(frame, &cupsoptions,
1068
0
            lp_cups_options(talloc_tos(), lp_sub, snum), &size)) {
1069
0
    goto out;
1070
0
  }
1071
0
  num_options = 0;
1072
0
  options     = NULL;
1073
0
  num_options = cupsParseOptions(cupsoptions, num_options, &options);
1074
1075
0
  if ( num_options )
1076
0
    cupsEncodeOptions(request, num_options, options);
1077
1078
       /*
1079
  * Do the request and get back a response...
1080
  */
1081
1082
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1083
0
           uri,
1084
0
           sizeof(uri),
1085
0
           "ipp",
1086
0
           NULL, /* username */
1087
0
           "localhost",
1088
0
           ippPort(),
1089
0
           "/printers/%s",
1090
0
           printername);
1091
0
  if (ustatus != HTTP_URI_STATUS_OK) {
1092
0
    goto out;
1093
0
  }
1094
1095
0
  if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1096
0
    goto out;
1097
0
  }
1098
0
  if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1099
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1100
0
      DEBUG(0,("Unable to print file to %s - %s\n",
1101
0
         lp_printername(talloc_tos(), lp_sub, snum),
1102
0
               ippErrorString(cupsLastError())));
1103
0
    } else {
1104
0
      ret = 0;
1105
0
      attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
1106
0
      if(attr_job_id) {
1107
0
        pjob->sysjob = ippGetInteger(attr_job_id, 0);
1108
0
        DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
1109
0
      } else {
1110
0
        DEBUG(0,("Missing job-id attribute in IPP response\n"));
1111
0
      }
1112
0
    }
1113
0
  } else {
1114
0
    DEBUG(0,("Unable to print file to `%s' - %s\n",
1115
0
       lp_printername(talloc_tos(), lp_sub, snum),
1116
0
       ippErrorString(cupsLastError())));
1117
0
  }
1118
1119
0
  if ( ret == 0 )
1120
0
    unlink(pjob->filename);
1121
  /* else print_job_end will do it for us */
1122
1123
0
 out:
1124
0
  if (response)
1125
0
    ippDelete(response);
1126
1127
0
  if (language)
1128
0
    cupsLangFree(language);
1129
1130
0
  if (http)
1131
0
    httpClose(http);
1132
1133
0
  if (num_options) {
1134
0
    cupsFreeOptions(num_options, options);
1135
0
  }
1136
0
  TALLOC_FREE(frame);
1137
1138
0
  return ret;
1139
0
}
1140
1141
/*
1142
 * 'cups_queue_get()' - Get all the jobs in the print queue.
1143
 */
1144
1145
static int cups_queue_get(const char *sharename,
1146
               enum printing_types printing_type,
1147
               char *lpq_command,
1148
               print_queue_struct **q,
1149
               print_status_struct *status)
1150
0
{
1151
0
  TALLOC_CTX *frame = talloc_stackframe();
1152
0
  char *printername = NULL;
1153
0
  http_t    *http = NULL;   /* HTTP connection to server */
1154
0
  ipp_t   *request = NULL, /* IPP Request */
1155
0
      *response = NULL; /* IPP Response */
1156
0
  ipp_attribute_t *attr = NULL;   /* Current attribute */
1157
0
  cups_lang_t *language = NULL; /* Default language */
1158
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1159
0
  http_uri_status_t ustatus;
1160
0
  int   qcount = 0,   /* Number of active queue entries */
1161
0
      qalloc = 0;   /* Number of queue entries allocated */
1162
0
  print_queue_struct *queue = NULL, /* Queue entries */
1163
0
      *temp;    /* Temporary pointer for queue */
1164
0
  char    *user_name = NULL, /* job-originating-user-name attribute */
1165
0
      *job_name = NULL; /* job-name attribute */
1166
0
  int   job_id;   /* job-id attribute */
1167
0
  int   job_k_octets; /* job-k-octets attribute */
1168
0
  time_t    job_time; /* time-at-creation attribute */
1169
0
  ipp_jstate_t  job_status; /* job-status attribute */
1170
0
  int   job_priority; /* job-priority attribute */
1171
0
  size_t size;
1172
0
  static const char *jattrs[] = /* Requested job attributes */
1173
0
      {
1174
0
        "job-id",
1175
0
        "job-k-octets",
1176
0
        "job-name",
1177
0
        "job-originating-user-name",
1178
0
        "job-priority",
1179
0
        "job-state",
1180
0
        "time-at-creation",
1181
0
      };
1182
0
  static const char *pattrs[] = /* Requested printer attributes */
1183
0
      {
1184
0
        "printer-state",
1185
0
        "printer-state-message"
1186
0
      };
1187
1188
0
  *q = NULL;
1189
1190
  /* HACK ALERT!!!  The problem with support the 'printer name'
1191
     option is that we key the tdb off the sharename.  So we will
1192
     overload the lpq_command string to pass in the printername
1193
     (which is basically what we do for non-cups printers ... using
1194
     the lpq_command to get the queue listing). */
1195
1196
0
  if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1197
0
    goto out;
1198
0
  }
1199
0
  DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1200
1201
       /*
1202
        * Make sure we don't ask for passwords...
1203
  */
1204
1205
0
        cupsSetPasswordCB(cups_passwd_cb);
1206
1207
       /*
1208
  * Try to connect to the server...
1209
  */
1210
1211
0
  if ((http = cups_connect(frame)) == NULL) {
1212
0
    goto out;
1213
0
  }
1214
1215
       /*
1216
        * Generate the printer URI...
1217
  */
1218
1219
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1220
0
           uri,
1221
0
           sizeof(uri),
1222
0
           "ipp",
1223
0
           NULL, /* username */
1224
0
           "localhost",
1225
0
           ippPort(),
1226
0
           "/printers/%s",
1227
0
           printername);
1228
0
  if (ustatus != HTTP_URI_STATUS_OK) {
1229
0
    goto out;
1230
0
  }
1231
1232
       /*
1233
  * Build an IPP_GET_JOBS request, which requires the following
1234
  * attributes:
1235
  *
1236
  *    attributes-charset
1237
  *    attributes-natural-language
1238
  *    requested-attributes
1239
  *    printer-uri
1240
  */
1241
1242
0
  request = ippNew();
1243
1244
0
  ippSetOperation(request, IPP_GET_JOBS);
1245
0
  ippSetRequestId(request, 1);
1246
1247
0
  language = cupsLangDefault();
1248
1249
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1250
0
                     "attributes-charset", NULL, "utf-8");
1251
1252
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1253
0
                     "attributes-natural-language", NULL, language->language);
1254
1255
0
        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1256
0
                "requested-attributes",
1257
0
          (sizeof(jattrs) / sizeof(jattrs[0])),
1258
0
          NULL, jattrs);
1259
1260
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1261
0
                     "printer-uri", NULL, uri);
1262
1263
       /*
1264
  * Do the request and get back a response...
1265
  */
1266
1267
0
  if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1268
0
    DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1269
0
       ippErrorString(cupsLastError())));
1270
0
    goto out;
1271
0
  }
1272
1273
0
  if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1274
0
    DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1275
0
       ippErrorString(ippGetStatusCode(response))));
1276
0
    goto out;
1277
0
  }
1278
1279
       /*
1280
        * Process the jobs...
1281
  */
1282
1283
0
        qcount = 0;
1284
0
  qalloc = 0;
1285
0
  queue  = NULL;
1286
1287
0
        for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) {
1288
         /*
1289
    * Skip leading attributes until we hit a job...
1290
    */
1291
1292
0
    while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_JOB)
1293
0
      attr = ippNextAttribute(response);
1294
1295
0
    if (attr == NULL)
1296
0
      break;
1297
1298
         /*
1299
          * Allocate memory as needed...
1300
    */
1301
0
    if (qcount >= qalloc) {
1302
0
      qalloc += 16;
1303
1304
0
      queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1305
1306
0
      if (queue == NULL) {
1307
0
        DEBUG(0,("cups_queue_get: Not enough memory!\n"));
1308
0
        qcount = 0;
1309
0
        goto out;
1310
0
      }
1311
0
    }
1312
1313
0
    temp = queue + qcount;
1314
0
    memset(temp, 0, sizeof(print_queue_struct));
1315
1316
         /*
1317
    * Pull the needed attributes from this job...
1318
    */
1319
1320
0
    job_id       = 0;
1321
0
    job_priority = 50;
1322
0
    job_status   = IPP_JOB_PENDING;
1323
0
    job_time     = 0;
1324
0
    job_k_octets = 0;
1325
0
    user_name    = NULL;
1326
0
    job_name     = NULL;
1327
1328
0
    while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB) {
1329
0
      if (ippGetName(attr) == NULL) {
1330
0
        attr = ippNextAttribute(response);
1331
0
        break;
1332
0
      }
1333
1334
0
      if (strcmp(ippGetName(attr), "job-id") == 0 &&
1335
0
          ippGetValueTag(attr) == IPP_TAG_INTEGER)
1336
0
        job_id = ippGetInteger(attr, 0);
1337
1338
0
      if (strcmp(ippGetName(attr), "job-k-octets") == 0 &&
1339
0
          ippGetValueTag(attr) == IPP_TAG_INTEGER)
1340
0
        job_k_octets = ippGetInteger(attr, 0);
1341
1342
0
      if (strcmp(ippGetName(attr), "job-priority") == 0 &&
1343
0
          ippGetValueTag(attr) == IPP_TAG_INTEGER)
1344
0
        job_priority = ippGetInteger(attr, 0);
1345
1346
0
      if (strcmp(ippGetName(attr), "job-state") == 0 &&
1347
0
          ippGetValueTag(attr) == IPP_TAG_ENUM)
1348
0
        job_status = (ipp_jstate_t)ippGetInteger(attr, 0);
1349
1350
0
      if (strcmp(ippGetName(attr), "time-at-creation") == 0 &&
1351
0
          ippGetValueTag(attr) == IPP_TAG_INTEGER)
1352
0
        job_time = ippGetInteger(attr, 0);
1353
1354
0
      if (strcmp(ippGetName(attr), "job-name") == 0 &&
1355
0
          ippGetValueTag(attr) == IPP_TAG_NAME) {
1356
0
        if (!pull_utf8_talloc(frame,
1357
0
            &job_name,
1358
0
            ippGetString(attr, 0, NULL),
1359
0
            &size)) {
1360
0
          goto out;
1361
0
        }
1362
0
      }
1363
1364
0
      if (strcmp(ippGetName(attr), "job-originating-user-name") == 0 &&
1365
0
          ippGetValueTag(attr) == IPP_TAG_NAME) {
1366
0
        if (!pull_utf8_talloc(frame,
1367
0
            &user_name,
1368
0
            ippGetString(attr, 0, NULL),
1369
0
            &size)) {
1370
0
          goto out;
1371
0
        }
1372
0
      }
1373
1374
0
      attr = ippNextAttribute(response);
1375
0
    }
1376
1377
         /*
1378
    * See if we have everything needed...
1379
    */
1380
1381
0
    if (user_name == NULL || job_name == NULL || job_id == 0) {
1382
0
      if (attr == NULL)
1383
0
        break;
1384
0
      else
1385
0
        continue;
1386
0
    }
1387
1388
0
    temp->sysjob   = job_id;
1389
0
    temp->size     = job_k_octets * 1024;
1390
0
    temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1391
0
         job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1392
0
                                 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1393
0
               LPQ_PRINTING;
1394
0
    temp->priority = job_priority;
1395
0
    temp->time     = job_time;
1396
0
    strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1397
0
    strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1398
1399
0
    qcount ++;
1400
1401
0
    if (attr == NULL)
1402
0
      break;
1403
0
  }
1404
1405
0
  ippDelete(response);
1406
0
  response = NULL;
1407
1408
       /*
1409
  * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1410
  * following attributes:
1411
  *
1412
  *    attributes-charset
1413
  *    attributes-natural-language
1414
  *    requested-attributes
1415
  *    printer-uri
1416
  */
1417
1418
0
  request = ippNew();
1419
1420
0
  ippSetOperation(request, IPP_GET_PRINTER_ATTRIBUTES);
1421
0
  ippSetRequestId(request, 1);
1422
1423
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1424
0
                     "attributes-charset", NULL, "utf-8");
1425
1426
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1427
0
                     "attributes-natural-language", NULL, language->language);
1428
1429
0
        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1430
0
                "requested-attributes",
1431
0
          (sizeof(pattrs) / sizeof(pattrs[0])),
1432
0
          NULL, pattrs);
1433
1434
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1435
0
                     "printer-uri", NULL, uri);
1436
1437
       /*
1438
  * Do the request and get back a response...
1439
  */
1440
1441
0
  if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1442
0
    DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1443
0
       ippErrorString(cupsLastError())));
1444
0
    goto out;
1445
0
  }
1446
1447
0
  if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1448
0
    DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1449
0
       ippErrorString(ippGetStatusCode(response))));
1450
0
    goto out;
1451
0
  }
1452
1453
       /*
1454
        * Get the current printer status and convert it to the SAMBA values.
1455
  */
1456
1457
0
        if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1458
0
    if (ippGetInteger(attr, 0) == IPP_PRINTER_STOPPED)
1459
0
      status->status = LPSTAT_STOPPED;
1460
0
    else
1461
0
      status->status = LPSTAT_OK;
1462
0
  }
1463
1464
0
        if ((attr = ippFindAttribute(response, "printer-state-message",
1465
0
                               IPP_TAG_TEXT)) != NULL) {
1466
0
    char *msg = NULL;
1467
0
    if (!pull_utf8_talloc(frame, &msg,
1468
0
        ippGetString(attr, 0, NULL),
1469
0
        &size)) {
1470
0
      SAFE_FREE(queue);
1471
0
      qcount = 0;
1472
0
      goto out;
1473
0
    }
1474
0
          fstrcpy(status->message, msg);
1475
0
  }
1476
1477
0
 out:
1478
1479
       /*
1480
        * Return the job queue...
1481
  */
1482
1483
0
  *q = queue;
1484
1485
0
  if (response)
1486
0
    ippDelete(response);
1487
1488
0
  if (language)
1489
0
    cupsLangFree(language);
1490
1491
0
  if (http)
1492
0
    httpClose(http);
1493
1494
0
  TALLOC_FREE(frame);
1495
0
  return qcount;
1496
0
}
1497
1498
1499
/*
1500
 * 'cups_queue_pause()' - Pause a print queue.
1501
 */
1502
1503
static int cups_queue_pause(int snum)
1504
0
{
1505
0
  TALLOC_CTX *frame = talloc_stackframe();
1506
0
  const struct loadparm_substitution *lp_sub =
1507
0
    loadparm_s3_global_substitution();
1508
0
  int   ret = 1;    /* Return value */
1509
0
  http_t    *http = NULL;   /* HTTP connection to server */
1510
0
  ipp_t   *request = NULL, /* IPP Request */
1511
0
      *response = NULL; /* IPP Response */
1512
0
  cups_lang_t *language = NULL; /* Default language */
1513
0
  char *printername = NULL;
1514
0
  char *username = NULL;
1515
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1516
0
  http_uri_status_t ustatus;
1517
0
  size_t size;
1518
1519
0
  DEBUG(5,("cups_queue_pause(%d)\n", snum));
1520
1521
  /*
1522
   * Make sure we don't ask for passwords...
1523
   */
1524
1525
0
        cupsSetPasswordCB(cups_passwd_cb);
1526
1527
  /*
1528
   * Try to connect to the server...
1529
   */
1530
1531
0
  if ((http = cups_connect(frame)) == NULL) {
1532
0
    goto out;
1533
0
  }
1534
1535
  /*
1536
   * Build an IPP_PAUSE_PRINTER request, which requires the following
1537
   * attributes:
1538
   *
1539
   *    attributes-charset
1540
   *    attributes-natural-language
1541
   *    printer-uri
1542
   *    requesting-user-name
1543
   */
1544
1545
0
  request = ippNew();
1546
1547
0
  ippSetOperation(request, IPP_PAUSE_PRINTER);
1548
0
  ippSetRequestId(request, 1);
1549
1550
0
  language = cupsLangDefault();
1551
1552
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1553
0
                     "attributes-charset", NULL, "utf-8");
1554
1555
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1556
0
               "attributes-natural-language", NULL, language->language);
1557
1558
0
  if (!push_utf8_talloc(frame, &printername,
1559
0
            lp_printername(talloc_tos(), lp_sub, snum), &size)) {
1560
0
    goto out;
1561
0
  }
1562
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1563
0
           uri,
1564
0
           sizeof(uri),
1565
0
           "ipp",
1566
0
           NULL, /* username */
1567
0
           "localhost",
1568
0
           ippPort(),
1569
0
           "/printers/%s",
1570
0
           printername);
1571
0
  if (ustatus != HTTP_URI_STATUS_OK) {
1572
0
    goto out;
1573
0
  }
1574
1575
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1576
1577
0
  if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1578
0
    goto out;
1579
0
  }
1580
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1581
0
               NULL, username);
1582
1583
       /*
1584
  * Do the request and get back a response...
1585
  */
1586
1587
0
  if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1588
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1589
0
      DEBUG(0,("Unable to pause printer %s - %s\n",
1590
0
         lp_printername(talloc_tos(), lp_sub, snum),
1591
0
        ippErrorString(cupsLastError())));
1592
0
    } else {
1593
0
      ret = 0;
1594
0
    }
1595
0
  } else {
1596
0
    DEBUG(0,("Unable to pause printer %s - %s\n",
1597
0
       lp_printername(talloc_tos(), lp_sub, snum),
1598
0
      ippErrorString(cupsLastError())));
1599
0
  }
1600
1601
0
 out:
1602
0
  if (response)
1603
0
    ippDelete(response);
1604
1605
0
  if (language)
1606
0
    cupsLangFree(language);
1607
1608
0
  if (http)
1609
0
    httpClose(http);
1610
1611
0
  TALLOC_FREE(frame);
1612
0
  return ret;
1613
0
}
1614
1615
1616
/*
1617
 * 'cups_queue_resume()' - Restart a print queue.
1618
 */
1619
1620
static int cups_queue_resume(int snum)
1621
0
{
1622
0
  TALLOC_CTX *frame = talloc_stackframe();
1623
0
  const struct loadparm_substitution *lp_sub =
1624
0
    loadparm_s3_global_substitution();
1625
0
  int   ret = 1;    /* Return value */
1626
0
  http_t    *http = NULL;   /* HTTP connection to server */
1627
0
  ipp_t   *request = NULL, /* IPP Request */
1628
0
      *response = NULL; /* IPP Response */
1629
0
  cups_lang_t *language = NULL; /* Default language */
1630
0
  char *printername = NULL;
1631
0
  char *username = NULL;
1632
0
  char    uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1633
0
  http_uri_status_t ustatus;
1634
0
  size_t size;
1635
1636
0
  DEBUG(5,("cups_queue_resume(%d)\n", snum));
1637
1638
       /*
1639
        * Make sure we don't ask for passwords...
1640
  */
1641
1642
0
        cupsSetPasswordCB(cups_passwd_cb);
1643
1644
       /*
1645
  * Try to connect to the server...
1646
  */
1647
1648
0
  if ((http = cups_connect(frame)) == NULL) {
1649
0
    goto out;
1650
0
  }
1651
1652
       /*
1653
  * Build an IPP_RESUME_PRINTER request, which requires the following
1654
  * attributes:
1655
  *
1656
  *    attributes-charset
1657
  *    attributes-natural-language
1658
  *    printer-uri
1659
  *    requesting-user-name
1660
  */
1661
1662
0
  request = ippNew();
1663
1664
0
  ippSetOperation(request, IPP_RESUME_PRINTER);
1665
0
  ippSetRequestId(request, 1);
1666
1667
0
  language = cupsLangDefault();
1668
1669
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1670
0
                     "attributes-charset", NULL, "utf-8");
1671
1672
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1673
0
               "attributes-natural-language", NULL, language->language);
1674
1675
0
  if (!push_utf8_talloc(frame, &printername, lp_printername(talloc_tos(), lp_sub, snum),
1676
0
            &size)) {
1677
0
    goto out;
1678
0
  }
1679
0
  ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1680
0
           uri,
1681
0
           sizeof(uri),
1682
0
           "ipp",
1683
0
           NULL, /* username */
1684
0
           "localhost",
1685
0
           ippPort(),
1686
0
           "/printers/%s",
1687
0
           printername);
1688
0
  if (ustatus != HTTP_URI_STATUS_OK) {
1689
0
    goto out;
1690
0
  }
1691
1692
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1693
1694
0
  if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1695
0
    goto out;
1696
0
  }
1697
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1698
0
               NULL, username);
1699
1700
       /*
1701
  * Do the request and get back a response...
1702
  */
1703
1704
0
  if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1705
0
    if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1706
0
      DEBUG(0,("Unable to resume printer %s - %s\n",
1707
0
         lp_printername(talloc_tos(), lp_sub, snum),
1708
0
        ippErrorString(cupsLastError())));
1709
0
    } else {
1710
0
      ret = 0;
1711
0
    }
1712
0
  } else {
1713
0
    DEBUG(0,("Unable to resume printer %s - %s\n",
1714
0
       lp_printername(talloc_tos(), lp_sub, snum),
1715
0
      ippErrorString(cupsLastError())));
1716
0
  }
1717
1718
0
 out:
1719
0
  if (response)
1720
0
    ippDelete(response);
1721
1722
0
  if (language)
1723
0
    cupsLangFree(language);
1724
1725
0
  if (http)
1726
0
    httpClose(http);
1727
1728
  TALLOC_FREE(frame);
1729
0
  return ret;
1730
0
}
1731
1732
/*******************************************************************
1733
 * CUPS printing interface definitions...
1734
 ******************************************************************/
1735
1736
struct printif  cups_printif =
1737
{
1738
  PRINT_CUPS,
1739
  cups_queue_get,
1740
  cups_queue_pause,
1741
  cups_queue_resume,
1742
  cups_job_delete,
1743
  cups_job_pause,
1744
  cups_job_resume,
1745
  cups_job_submit,
1746
};
1747
1748
#else
1749
 /* this keeps fussy compilers happy */
1750
 void print_cups_dummy(void);
1751
 void print_cups_dummy(void) {}
1752
#endif /* HAVE_CUPS */