root/source3/printing/print_iprint.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iprint_passwd_cb
  2. iprint_server
  3. iprint_get_server_version
  4. iprint_cache_add_printer
  5. iprint_cache_reload
  6. iprint_job_delete
  7. iprint_job_pause
  8. iprint_job_resume
  9. iprint_job_submit
  10. iprint_queue_get
  11. iprint_queue_pause
  12. iprint_queue_resume
  13. print_iprint_dummy

   1 /*
   2  * Support code for Novell iPrint using the Common UNIX Printing
   3  * System ("CUPS") libraries
   4  *
   5  * Copyright 1999-2003 by Michael R Sweet.
   6  * Portions Copyright 2005 by Joel J. Smith.
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License as published by
  10  * the Free Software Foundation; either version 3 of the License, or
  11  * (at your option) any later version.
  12  * 
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  * 
  18  * You should have received a copy of the GNU General Public License
  19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  20  */
  21 
  22 #include "includes.h"
  23 #include "printing.h"
  24 
  25 #ifdef HAVE_IPRINT
  26 #include <cups/cups.h>
  27 #include <cups/language.h>
  28 
  29 #define OPERATION_NOVELL_LIST_PRINTERS          0x401A
  30 #define OPERATION_NOVELL_MGMT                   0x401C
  31 #define NOVELL_SERVER_SYSNAME                   "sysname="
  32 #define NOVELL_SERVER_SYSNAME_NETWARE           "NetWare IA32"
  33 #define NOVELL_SERVER_VERSION_STRING            "iprintserverversion="
  34 #define NOVELL_SERVER_VERSION_OES_SP1           33554432
  35 
  36 /*
  37  * 'iprint_passwd_cb()' - The iPrint password callback...
  38  */
  39 
  40 static const char *                             /* O - Password or NULL */
  41 iprint_passwd_cb(const char *prompt)    /* I - Prompt */
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43        /*
  44         * Always return NULL to indicate that no password is available...
  45         */
  46 
  47         return (NULL);
  48 }
  49 
  50 static const char *iprint_server(void)
     /* [<][>][^][v][top][bottom][index][help] */
  51 {
  52         if ((lp_iprint_server() != NULL) && (strlen(lp_iprint_server()) > 0)) {
  53                 DEBUG(10, ("iprint server explicitly set to %s\n",
  54                            lp_iprint_server()));
  55                 return lp_iprint_server();
  56         }
  57 
  58         DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
  59         return cupsServer();
  60 }
  61 
  62 /*
  63  * Pass in an already connected http_t*
  64  * Returns the server version if one can be found, multiplied by
  65  * -1 for all NetWare versions.  Returns 0 if a server version
  66  * cannot be determined
  67  */
  68 
  69 static int iprint_get_server_version(http_t *http, char* serviceUri)
     /* [<][>][^][v][top][bottom][index][help] */
  70 {
  71         ipp_t           *request = NULL,        /* IPP Request */
  72                         *response = NULL;       /* IPP Response */
  73         ipp_attribute_t *attr;                  /* Current attribute */
  74         cups_lang_t     *language = NULL;       /* Default language */
  75         char            *ver;                   /* server version pointer */
  76         char            *vertmp;                /* server version tmp pointer */
  77         int             serverVersion = 0;      /* server version */
  78         char            *os;                    /* server os */
  79         int             osFlag = 0;             /* 0 for NetWare, 1 for anything else */
  80         char            *temp;                  /* pointer for string manipulation */
  81 
  82        /*
  83         * Build an OPERATION_NOVELL_MGMT("get-server-version") request,
  84         * which requires the following attributes:
  85         *
  86         *    attributes-charset
  87         *    attributes-natural-language
  88         *    operation-name
  89         *    service-uri
  90         */
  91 
  92         request = ippNew();
  93 
  94         request->request.op.operation_id = (ipp_op_t)OPERATION_NOVELL_MGMT;
  95         request->request.op.request_id   = 1;
  96 
  97         language = cupsLangDefault();
  98 
  99         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 100                      "attributes-charset", NULL, "utf-8");
 101 
 102         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 103                      "attributes-natural-language", NULL, language->language);
 104 
 105         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
 106                      "service-uri", NULL, serviceUri);
 107 
 108         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 109                       "operation-name", NULL, "get-server-version");
 110 
 111        /*
 112         * Do the request and get back a response...
 113         */
 114 
 115         if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) ||
 116             (response->request.status.status_code >= IPP_OK_CONFLICT))
 117                 goto out;
 118 
 119         if (((attr = ippFindAttribute(response, "server-version",
 120                                       IPP_TAG_STRING)) != NULL)) {
 121                 if ((ver = strstr(attr->values[0].string.text,
 122                                   NOVELL_SERVER_VERSION_STRING)) != NULL) {
 123                         ver += strlen(NOVELL_SERVER_VERSION_STRING);
 124                        /*
 125                         * Strangely, libcups stores a IPP_TAG_STRING (octet
 126                         * string) as a null-terminated string with no length
 127                         * even though it could be binary data with nulls in
 128                         * it.  Luckily, in this case the value is not binary.
 129                         */
 130                         serverVersion = strtol(ver, &vertmp, 10);
 131 
 132                         /* Check for not found, overflow or negative version */
 133                         if ((ver == vertmp) || (serverVersion < 0))
 134                                 serverVersion = 0;
 135                 }
 136 
 137                 if ((os = strstr(attr->values[0].string.text,
 138                                   NOVELL_SERVER_SYSNAME)) != NULL) {
 139                         os += strlen(NOVELL_SERVER_SYSNAME);
 140                         if ((temp = strchr(os,'<')) != NULL)
 141                                 *temp = '\0';
 142                         if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
 143                                 osFlag = 1; /* 1 for non-NetWare systems */
 144                 }
 145         }
 146 
 147  out:
 148         if (response)
 149                 ippDelete(response);
 150 
 151         if (language)
 152                 cupsLangFree(language);
 153 
 154         if (osFlag == 0)
 155                 serverVersion *= -1;
 156 
 157         return serverVersion;
 158 }
 159 
 160 
 161 static int iprint_cache_add_printer(http_t *http,
     /* [<][>][^][v][top][bottom][index][help] */
 162                                    int reqId,
 163                                    char* url)
 164 {
 165         ipp_t           *request = NULL,        /* IPP Request */
 166                         *response = NULL;       /* IPP Response */
 167         ipp_attribute_t *attr;                  /* Current attribute */
 168         cups_lang_t     *language = NULL;       /* Default language */
 169         char            *name,                  /* printer-name attribute */
 170                         *info,                  /* printer-info attribute */
 171                         smb_enabled,            /* smb-enabled attribute */
 172                         secure;                 /* security-enabled attrib. */
 173 
 174         char            *httpPath;      /* path portion of the printer-uri */
 175 
 176         static const char *pattrs[] =   /* Requested printer attributes */
 177                         {
 178                           "printer-name",
 179                           "security-enabled",
 180                           "printer-info",
 181                           "smb-enabled"
 182                         };       
 183 
 184         request = ippNew();
 185 
 186         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
 187         request->request.op.request_id   = reqId;
 188 
 189         language = cupsLangDefault();
 190 
 191         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 192                      "attributes-charset", NULL, "utf-8");
 193 
 194         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 195                      "attributes-natural-language", NULL, language->language);
 196 
 197         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url);
 198 
 199         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 200                       "requested-attributes",
 201                       (sizeof(pattrs) / sizeof(pattrs[0])),
 202                       NULL, pattrs);
 203 
 204         /*
 205          * Do the request and get back a response...
 206          */
 207 
 208         if ((httpPath = strstr(url,"://")) == NULL ||
 209                         (httpPath = strchr(httpPath+3,'/')) == NULL)
 210         {
 211                 ippDelete(request);
 212                 request = NULL;
 213                 goto out;
 214         }
 215 
 216         if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
 217                 ipp_status_t lastErr = cupsLastError();
 218 
 219                /*
 220                 * Ignore printers that cannot be queried without credentials
 221                 */
 222                 if (lastErr == IPP_FORBIDDEN || 
 223                     lastErr == IPP_NOT_AUTHENTICATED ||
 224                     lastErr == IPP_NOT_AUTHORIZED)
 225                         goto out;
 226 
 227                 DEBUG(0,("Unable to get printer list - %s\n",
 228                       ippErrorString(lastErr)));
 229                 goto out;
 230         }
 231 
 232         for (attr = response->attrs; attr != NULL;) {
 233                /*
 234                 * Skip leading attributes until we hit a printer...
 235                 */
 236 
 237                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
 238                         attr = attr->next;
 239 
 240                 if (attr == NULL)
 241                         break;
 242 
 243                /*
 244                 * Pull the needed attributes from this printer...
 245                 */
 246 
 247                 name       = NULL;
 248                 info       = NULL;
 249                 smb_enabled= 1;
 250                 secure     = 0;
 251 
 252                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
 253                         if (strcmp(attr->name, "printer-name") == 0 &&
 254                             attr->value_tag == IPP_TAG_NAME)
 255                                 name = attr->values[0].string.text;
 256 
 257                         if (strcmp(attr->name, "printer-info") == 0 &&
 258                             (attr->value_tag == IPP_TAG_TEXT ||
 259                             attr->value_tag == IPP_TAG_TEXTLANG))
 260                                 info = attr->values[0].string.text;
 261 
 262                        /*
 263                         * If the smb-enabled attribute is present and the
 264                         * value is set to 0, don't show the printer.
 265                         * If the attribute is not present, assume that the
 266                         * printer should show up
 267                         */
 268                         if (!strcmp(attr->name, "smb-enabled") &&
 269                             ((attr->value_tag == IPP_TAG_INTEGER &&
 270                             !attr->values[0].integer) ||
 271                             (attr->value_tag == IPP_TAG_BOOLEAN &&
 272                             !attr->values[0].boolean)))
 273                                 smb_enabled = 0;
 274 
 275                        /*
 276                         * If the security-enabled attribute is present and the
 277                         * value is set to 1, don't show the printer.
 278                         * If the attribute is not present, assume that the
 279                         * printer should show up
 280                         */
 281                         if (!strcmp(attr->name, "security-enabled") &&
 282                             ((attr->value_tag == IPP_TAG_INTEGER &&
 283                             attr->values[0].integer) ||
 284                             (attr->value_tag == IPP_TAG_BOOLEAN &&
 285                             attr->values[0].boolean)))
 286                                 secure = 1;
 287 
 288                         attr = attr->next;
 289                 }
 290 
 291                /*
 292                 * See if we have everything needed...
 293                 * Make sure the printer is not a secure printer
 294                 * and make sure smb printing hasn't been explicitly
 295                 * disabled for the printer
 296                 */
 297 
 298                 if (name != NULL && !secure && smb_enabled) 
 299                         pcap_cache_add(name, info);
 300         }
 301 
 302  out:
 303         if (response)
 304                 ippDelete(response);
 305         return(0);
 306 }
 307 
 308 bool iprint_cache_reload(void)
     /* [<][>][^][v][top][bottom][index][help] */
 309 {
 310         http_t          *http = NULL;           /* HTTP connection to server */
 311         ipp_t           *request = NULL,        /* IPP Request */
 312                         *response = NULL;       /* IPP Response */
 313         ipp_attribute_t *attr;                  /* Current attribute */
 314         cups_lang_t     *language = NULL;       /* Default language */
 315         int             i;
 316         bool ret = False;
 317 
 318         DEBUG(5, ("reloading iprint printcap cache\n"));
 319 
 320        /*
 321         * Make sure we don't ask for passwords...
 322         */
 323 
 324         cupsSetPasswordCB(iprint_passwd_cb);
 325 
 326        /*
 327         * Try to connect to the server...
 328         */
 329 
 330         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 331                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 332                          iprint_server(), strerror(errno)));
 333                 goto out;
 334         }
 335 
 336        /*
 337         * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
 338         *
 339         *    attributes-charset
 340         *    attributes-natural-language
 341         */
 342 
 343         request = ippNew();
 344 
 345         request->request.op.operation_id =
 346                 (ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS;
 347         request->request.op.request_id   = 1;
 348 
 349         language = cupsLangDefault();
 350 
 351         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 352                      "attributes-charset", NULL, "utf-8");
 353 
 354         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 355                      "attributes-natural-language", NULL, language->language);
 356 
 357         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 358                      "ipp-server", NULL, "ippSrvr");
 359 
 360        /*
 361         * Do the request and get back a response...
 362         */
 363 
 364         if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) {
 365                 DEBUG(0,("Unable to get printer list - %s\n",
 366                          ippErrorString(cupsLastError())));
 367                 goto out;
 368         }
 369 
 370         for (attr = response->attrs; attr != NULL;) {
 371                /*
 372                 * Skip leading attributes until we hit a printer...
 373                 */
 374 
 375                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
 376                         attr = attr->next;
 377 
 378                 if (attr == NULL)
 379                         break;
 380 
 381                /*
 382                 * Pull the needed attributes from this printer...
 383                 */
 384 
 385                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
 386                 {
 387                         if (strcmp(attr->name, "printer-name") == 0 &&
 388                             (attr->value_tag == IPP_TAG_URI ||
 389                              attr->value_tag == IPP_TAG_NAME ||
 390                              attr->value_tag == IPP_TAG_TEXT ||
 391                              attr->value_tag == IPP_TAG_NAMELANG ||
 392                              attr->value_tag == IPP_TAG_TEXTLANG))
 393                         {
 394                                 for (i = 0; i<attr->num_values; i++)
 395                                 {
 396                                         char *url = attr->values[i].string.text;
 397                                         if (!url || !strlen(url))
 398                                                 continue;
 399                                         iprint_cache_add_printer(http, i+2, url);
 400                                 }
 401                         }
 402                         attr = attr->next;
 403                 }
 404         }
 405 
 406         ret = True;
 407 
 408  out:
 409         if (response)
 410                 ippDelete(response);
 411 
 412         if (language)
 413                 cupsLangFree(language);
 414 
 415         if (http)
 416                 httpClose(http);
 417 
 418         return ret;
 419 }
 420 
 421 
 422 /*
 423  * 'iprint_job_delete()' - Delete a job.
 424  */
 425 
 426 static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
     /* [<][>][^][v][top][bottom][index][help] */
 427 {
 428         int             ret = 1;                /* Return value */
 429         http_t          *http = NULL;           /* HTTP connection to server */
 430         ipp_t           *request = NULL,        /* IPP Request */
 431                         *response = NULL;       /* IPP Response */
 432         cups_lang_t     *language = NULL;       /* Default language */
 433         char            uri[HTTP_MAX_URI];      /* printer-uri attribute */
 434         char            httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
 435 
 436 
 437         DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
 438 
 439        /*
 440         * Make sure we don't ask for passwords...
 441         */
 442 
 443         cupsSetPasswordCB(iprint_passwd_cb);
 444 
 445        /*
 446         * Try to connect to the server...
 447         */
 448 
 449         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 450                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 451                          iprint_server(), strerror(errno)));
 452                 goto out;
 453         }
 454 
 455        /*
 456         * Build an IPP_CANCEL_JOB request, which uses the following
 457         * attributes:
 458         *
 459         *    attributes-charset
 460         *    attributes-natural-language
 461         *    printer-uri
 462         *    job-id
 463         *    requesting-user-name
 464         */
 465 
 466         request = ippNew();
 467 
 468         request->request.op.operation_id = IPP_CANCEL_JOB;
 469         request->request.op.request_id   = 1;
 470 
 471         language = cupsLangDefault();
 472 
 473         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 474                      "attributes-charset", NULL, "utf-8");
 475 
 476         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 477                      "attributes-natural-language", NULL, language->language);
 478 
 479         slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename);
 480 
 481         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
 482 
 483         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
 484 
 485         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
 486                      NULL, pjob->user);
 487 
 488        /*
 489         * Do the request and get back a response...
 490         */
 491 
 492         slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename);
 493 
 494         if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
 495                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
 496                         DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
 497                                 ippErrorString(cupsLastError())));
 498                 } else {
 499                         ret = 0;
 500                 }
 501         } else {
 502                 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
 503                         ippErrorString(cupsLastError())));
 504         }
 505 
 506  out:
 507         if (response)
 508                 ippDelete(response);
 509 
 510         if (language)
 511                 cupsLangFree(language);
 512 
 513         if (http)
 514                 httpClose(http);
 515 
 516         return ret;
 517 }
 518 
 519 
 520 /*
 521  * 'iprint_job_pause()' - Pause a job.
 522  */
 523 
 524 static int iprint_job_pause(int snum, struct printjob *pjob)
     /* [<][>][^][v][top][bottom][index][help] */
 525 {
 526         int             ret = 1;                /* Return value */
 527         http_t          *http = NULL;           /* HTTP connection to server */
 528         ipp_t           *request = NULL,        /* IPP Request */
 529                         *response = NULL;       /* IPP Response */
 530         cups_lang_t     *language = NULL;       /* Default language */
 531         char            uri[HTTP_MAX_URI];      /* printer-uri attribute */
 532         char            httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
 533 
 534 
 535         DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
 536 
 537        /*
 538         * Make sure we don't ask for passwords...
 539         */
 540 
 541         cupsSetPasswordCB(iprint_passwd_cb);
 542 
 543        /*
 544         * Try to connect to the server...
 545         */
 546 
 547         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 548                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 549                          iprint_server(), strerror(errno)));
 550                 goto out;
 551         }
 552 
 553        /*
 554         * Build an IPP_HOLD_JOB request, which requires the following
 555         * attributes:
 556         *
 557         *    attributes-charset
 558         *    attributes-natural-language
 559         *    printer-uri
 560         *    job-id
 561         *    requesting-user-name
 562         */
 563 
 564         request = ippNew();
 565 
 566         request->request.op.operation_id = IPP_HOLD_JOB;
 567         request->request.op.request_id   = 1;
 568 
 569         language = cupsLangDefault();
 570 
 571         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 572                      "attributes-charset", NULL, "utf-8");
 573 
 574         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 575                      "attributes-natural-language", NULL, language->language);
 576 
 577         slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
 578 
 579         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
 580 
 581         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
 582 
 583         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
 584                      NULL, pjob->user);
 585 
 586        /*
 587         * Do the request and get back a response...
 588         */
 589 
 590         slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
 591 
 592         if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
 593                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
 594                         DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
 595                                 ippErrorString(cupsLastError())));
 596                 } else {
 597                         ret = 0;
 598                 }
 599         } else {
 600                 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
 601                         ippErrorString(cupsLastError())));
 602         }
 603 
 604  out:
 605         if (response)
 606                 ippDelete(response);
 607 
 608         if (language)
 609                 cupsLangFree(language);
 610 
 611         if (http)
 612                 httpClose(http);
 613 
 614         return ret;
 615 }
 616 
 617 
 618 /*
 619  * 'iprint_job_resume()' - Resume a paused job.
 620  */
 621 
 622 static int iprint_job_resume(int snum, struct printjob *pjob)
     /* [<][>][^][v][top][bottom][index][help] */
 623 {
 624         int             ret = 1;                /* Return value */
 625         http_t          *http = NULL;           /* HTTP connection to server */
 626         ipp_t           *request = NULL,        /* IPP Request */
 627                         *response = NULL;       /* IPP Response */
 628         cups_lang_t     *language = NULL;       /* Default language */
 629         char            uri[HTTP_MAX_URI];      /* printer-uri attribute */
 630         char            httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
 631 
 632 
 633         DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
 634 
 635        /*
 636         * Make sure we don't ask for passwords...
 637         */
 638 
 639         cupsSetPasswordCB(iprint_passwd_cb);
 640 
 641        /*
 642         * Try to connect to the server...
 643         */
 644 
 645         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 646                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 647                          iprint_server(), strerror(errno)));
 648                 goto out;
 649         }
 650 
 651        /*
 652         * Build an IPP_RELEASE_JOB request, which requires the following
 653         * attributes:
 654         *
 655         *    attributes-charset
 656         *    attributes-natural-language
 657         *    printer-uri
 658         *    job-id
 659         *    requesting-user-name
 660         */
 661 
 662         request = ippNew();
 663 
 664         request->request.op.operation_id = IPP_RELEASE_JOB;
 665         request->request.op.request_id   = 1;
 666 
 667         language = cupsLangDefault();
 668 
 669         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 670                      "attributes-charset", NULL, "utf-8");
 671 
 672         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 673                      "attributes-natural-language", NULL, language->language);
 674 
 675         slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
 676 
 677         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
 678 
 679         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
 680 
 681         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
 682                      NULL, pjob->user);
 683 
 684        /*
 685         * Do the request and get back a response...
 686         */
 687 
 688         slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
 689 
 690         if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
 691                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
 692                         DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
 693                                 ippErrorString(cupsLastError())));
 694                 } else {
 695                         ret = 0;
 696                 }
 697         } else {
 698                 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
 699                         ippErrorString(cupsLastError())));
 700         }
 701 
 702  out:
 703         if (response)
 704                 ippDelete(response);
 705 
 706         if (language)
 707                 cupsLangFree(language);
 708 
 709         if (http)
 710                 httpClose(http);
 711 
 712         return ret;
 713 }
 714 
 715 
 716 /*
 717  * 'iprint_job_submit()' - Submit a job for printing.
 718  */
 719 
 720 static int iprint_job_submit(int snum, struct printjob *pjob)
     /* [<][>][^][v][top][bottom][index][help] */
 721 {
 722         int             ret = 1;                /* Return value */
 723         http_t          *http = NULL;           /* HTTP connection to server */
 724         ipp_t           *request = NULL,        /* IPP Request */
 725                         *response = NULL;       /* IPP Response */
 726         ipp_attribute_t *attr;          /* Current attribute */
 727         cups_lang_t     *language = NULL;       /* Default language */
 728         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
 729         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
 730         char addr[INET6_ADDRSTRLEN];
 731 
 732         DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
 733 
 734        /*
 735         * Make sure we don't ask for passwords...
 736         */
 737 
 738         cupsSetPasswordCB(iprint_passwd_cb);
 739 
 740        /*
 741         * Try to connect to the server...
 742         */
 743 
 744         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 745                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 746                          iprint_server(), strerror(errno)));
 747                 goto out;
 748         }
 749 
 750        /*
 751         * Build an IPP_PRINT_JOB request, which requires the following
 752         * attributes:
 753         *
 754         *    attributes-charset
 755         *    attributes-natural-language
 756         *    printer-uri
 757         *    requesting-user-name
 758         *    [document-data]
 759         */
 760 
 761         request = ippNew();
 762 
 763         request->request.op.operation_id = IPP_PRINT_JOB;
 764         request->request.op.request_id   = 1;
 765 
 766         language = cupsLangDefault();
 767 
 768         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 769                      "attributes-charset", NULL, "utf-8");
 770 
 771         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 772                      "attributes-natural-language", NULL, language->language);
 773 
 774         slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
 775 
 776         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
 777                      "printer-uri", NULL, uri);
 778 
 779         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
 780                      NULL, pjob->user);
 781 
 782         clientname = client_name(get_client_fd());
 783         if (strcmp(clientname, "UNKNOWN") == 0) {
 784                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
 785         }
 786         
 787         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
 788                      "job-originating-host-name", NULL,
 789                      clientname);
 790 
 791         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
 792                      pjob->jobname);
 793 
 794        /*
 795         * Do the request and get back a response...
 796         */
 797 
 798         slprintf(uri, sizeof(uri) - 1, "/ipp/%s", PRINTERNAME(snum));
 799 
 800         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
 801                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
 802                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
 803                                  ippErrorString(cupsLastError())));
 804                 } else {
 805                         ret = 0;
 806                 }
 807         } else {
 808                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
 809                          ippErrorString(cupsLastError())));
 810         }
 811 
 812         if ( ret == 0 )
 813                 unlink(pjob->filename);
 814         /* else print_job_end will do it for us */
 815 
 816         if ( ret == 0 ) {
 817 
 818                 attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
 819                 if (attr != NULL && attr->group_tag == IPP_TAG_JOB)
 820                 {
 821                         pjob->sysjob = attr->values[0].integer;
 822                 }
 823         }
 824 
 825  out:
 826         if (response)
 827                 ippDelete(response);
 828 
 829         if (language)
 830                 cupsLangFree(language);
 831 
 832         if (http)
 833                 httpClose(http);
 834 
 835         return ret;
 836 }
 837 
 838 /*
 839  * 'iprint_queue_get()' - Get all the jobs in the print queue.
 840  */
 841 
 842 static int iprint_queue_get(const char *sharename,
     /* [<][>][^][v][top][bottom][index][help] */
 843                             enum printing_types printing_type,
 844                             char *lpq_command,
 845                             print_queue_struct **q, 
 846                             print_status_struct *status)
 847 {
 848         fstring         printername;
 849         http_t          *http = NULL;           /* HTTP connection to server */
 850         ipp_t           *request = NULL,        /* IPP Request */
 851                         *response = NULL;       /* IPP Response */
 852         ipp_attribute_t *attr = NULL;           /* Current attribute */
 853         cups_lang_t     *language = NULL;       /* Default language */
 854         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
 855         char            serviceUri[HTTP_MAX_URI]; /* service-uri attribute */
 856         char            httpPath[HTTP_MAX_URI]; /* path portion of the uri */
 857         int             jobUseUnixTime = 0;     /* Whether job times should
 858                                                  * be assumed to be Unix time */
 859         int             qcount = 0,             /* Number of active queue entries */
 860                         qalloc = 0;             /* Number of queue entries allocated */
 861         print_queue_struct *queue = NULL,       /* Queue entries */
 862                         *temp;          /* Temporary pointer for queue */
 863         const char      *user_name,     /* job-originating-user-name attribute */
 864                         *job_name;      /* job-name attribute */
 865         int             job_id;         /* job-id attribute */
 866         int             job_k_octets;   /* job-k-octets attribute */
 867         time_t          job_time;       /* time-at-creation attribute */
 868         time_t          printer_current_time = 0;       /* printer's current time */
 869         time_t          printer_up_time = 0;    /* printer's uptime */
 870         ipp_jstate_t    job_status;     /* job-status attribute */
 871         int             job_priority;   /* job-priority attribute */
 872         static const char *jattrs[] =   /* Requested job attributes */
 873                         {
 874                           "job-id",
 875                           "job-k-octets",
 876                           "job-name",
 877                           "job-originating-user-name",
 878                           "job-priority",
 879                           "job-state",
 880                           "time-at-creation",
 881                         };
 882         static const char *pattrs[] =   /* Requested printer attributes */
 883                         {
 884                           "printer-state",
 885                           "printer-state-message",
 886                           "printer-current-time",
 887                           "printer-up-time"
 888                         };
 889 
 890         *q = NULL;
 891 
 892         /* HACK ALERT!!!  The porblem with support the 'printer name' 
 893            option is that we key the tdb off the sharename.  So we will 
 894            overload the lpq_command string to pass in the printername 
 895            (which is basically what we do for non-cups printers ... using 
 896            the lpq_command to get the queue listing). */
 897 
 898         fstrcpy( printername, lpq_command );
 899 
 900         DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername, q, status));
 901 
 902        /*
 903         * Make sure we don't ask for passwords...
 904         */
 905 
 906         cupsSetPasswordCB(iprint_passwd_cb);
 907 
 908        /*
 909         * Try to connect to the server...
 910         */
 911 
 912         if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
 913                 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 
 914                          iprint_server(), strerror(errno)));
 915                 goto out;
 916         }
 917 
 918        /*
 919         * Generate the printer URI and the service URI that goes with it...
 920         */
 921 
 922         slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), printername);
 923         slprintf(serviceUri, sizeof(serviceUri) - 1, "ipp://%s/ipp/", iprint_server());
 924 
 925        /*
 926         * For Linux iPrint servers from OES SP1 on, the iPrint server
 927         * uses Unix time for job start times unless it detects the iPrint
 928         * client in an http User-Agent header.  (This was done to accomodate
 929         * CUPS broken behavior.  According to RFC 2911, section 4.3.14, job
 930         * start times are supposed to be relative to how long the printer has
 931         * been up.)  Since libcups doesn't allow us to set that header before
 932         * the request is sent, this ugly hack allows us to detect the server
 933         * version and decide how to interpret the job time.
 934         */
 935         if (iprint_get_server_version(http, serviceUri) >=
 936             NOVELL_SERVER_VERSION_OES_SP1)
 937                 jobUseUnixTime = 1;
 938 
 939         request = ippNew();
 940 
 941         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
 942         request->request.op.request_id   = 2;
 943 
 944         language = cupsLangDefault();
 945 
 946         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
 947                      "attributes-charset", NULL, "utf-8");
 948 
 949         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
 950                      "attributes-natural-language", NULL, language->language);
 951 
 952         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
 953                      "printer-uri", NULL, uri);
 954 
 955         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 956                       "requested-attributes",
 957                       (sizeof(pattrs) / sizeof(pattrs[0])),
 958                       NULL, pattrs);
 959 
 960        /*
 961         * Do the request and get back a response...
 962         */
 963 
 964         slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
 965 
 966         if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
 967                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
 968                          ippErrorString(cupsLastError())));
 969                 *q = queue;
 970                 goto out;
 971         }
 972 
 973         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
 974                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
 975                          ippErrorString(response->request.status.status_code)));
 976                 *q = queue;
 977                 goto out;
 978         }
 979 
 980        /*
 981         * Get the current printer status and convert it to the SAMBA values.
 982         */
 983 
 984         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
 985                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
 986                         status->status = LPSTAT_STOPPED;
 987                 else
 988                         status->status = LPSTAT_OK;
 989         }
 990 
 991         if ((attr = ippFindAttribute(response, "printer-state-message",
 992                                      IPP_TAG_TEXT)) != NULL)
 993                 fstrcpy(status->message, attr->values[0].string.text);
 994 
 995         if ((attr = ippFindAttribute(response, "printer-current-time",
 996                                      IPP_TAG_DATE)) != NULL)
 997                 printer_current_time = ippDateToTime(attr->values[0].date);
 998 
 999         if ((attr = ippFindAttribute(response, "printer-up-time",
1000                                      IPP_TAG_INTEGER)) != NULL)
1001                 printer_up_time = attr->values[0].integer;
1002 
1003         ippDelete(response);
1004         response = NULL;
1005 
1006        /*
1007         * Build an IPP_GET_JOBS request, which requires the following
1008         * attributes:
1009         *
1010         *    attributes-charset
1011         *    attributes-natural-language
1012         *    requested-attributes
1013         *    printer-uri
1014         */
1015 
1016         request = ippNew();
1017 
1018         request->request.op.operation_id = IPP_GET_JOBS;
1019         request->request.op.request_id   = 3;
1020 
1021         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1022                      "attributes-charset", NULL, "utf-8");
1023 
1024         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1025                      "attributes-natural-language", NULL, language->language);
1026 
1027         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1028                      "printer-uri", NULL, uri);
1029 
1030         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1031                       "requested-attributes",
1032                       (sizeof(jattrs) / sizeof(jattrs[0])),
1033                       NULL, jattrs);
1034 
1035        /*
1036         * Do the request and get back a response...
1037         */
1038 
1039         slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
1040 
1041         if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
1042                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1043                          ippErrorString(cupsLastError())));
1044                 goto out;
1045         }
1046 
1047         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1048                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1049                          ippErrorString(response->request.status.status_code)));
1050                 goto out;
1051         }
1052 
1053        /*
1054         * Process the jobs...
1055         */
1056 
1057         qcount = 0;
1058         qalloc = 0;
1059         queue  = NULL;
1060 
1061         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1062                /*
1063                 * Skip leading attributes until we hit a job...
1064                 */
1065 
1066                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1067                         attr = attr->next;
1068 
1069                 if (attr == NULL)
1070                         break;
1071 
1072                /*
1073                 * Allocate memory as needed...
1074                 */
1075                 if (qcount >= qalloc) {
1076                         qalloc += 16;
1077 
1078                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1079 
1080                         if (queue == NULL) {
1081                                 DEBUG(0,("iprint_queue_get: Not enough memory!"));
1082                                 qcount = 0;
1083                                 goto out;
1084                         }
1085                 }
1086 
1087                 temp = queue + qcount;
1088                 memset(temp, 0, sizeof(print_queue_struct));
1089 
1090                /*
1091                 * Pull the needed attributes from this job...
1092                 */
1093 
1094                 job_id       = 0;
1095                 job_priority = 50;
1096                 job_status   = IPP_JOB_PENDING;
1097                 job_time     = 0;
1098                 job_k_octets = 0;
1099                 user_name    = NULL;
1100                 job_name     = NULL;
1101 
1102                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1103                         if (attr->name == NULL) {
1104                                 attr = attr->next;
1105                                 break;
1106                         }
1107 
1108                         if (strcmp(attr->name, "job-id") == 0 &&
1109                             attr->value_tag == IPP_TAG_INTEGER)
1110                                 job_id = attr->values[0].integer;
1111 
1112                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1113                             attr->value_tag == IPP_TAG_INTEGER)
1114                                 job_k_octets = attr->values[0].integer;
1115 
1116                         if (strcmp(attr->name, "job-priority") == 0 &&
1117                             attr->value_tag == IPP_TAG_INTEGER)
1118                                 job_priority = attr->values[0].integer;
1119 
1120                         if (strcmp(attr->name, "job-state") == 0 &&
1121                             attr->value_tag == IPP_TAG_ENUM)
1122                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1123 
1124                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1125                             attr->value_tag == IPP_TAG_INTEGER)
1126                         {
1127                                /*
1128                                 * If jobs times are in Unix time, the accuracy of the job
1129                                 * start time depends upon the iPrint server's time being
1130                                 * set correctly.  Otherwise, the accuracy depends upon
1131                                 * the Samba server's time being set correctly
1132                                 */
1133 
1134                                 if (jobUseUnixTime)
1135                                         job_time = attr->values[0].integer; 
1136                                 else
1137                                         job_time = time(NULL) - printer_up_time + attr->values[0].integer;
1138                         }
1139 
1140                         if (strcmp(attr->name, "job-name") == 0 &&
1141                             (attr->value_tag == IPP_TAG_NAMELANG ||
1142                              attr->value_tag == IPP_TAG_NAME))
1143                                 job_name = attr->values[0].string.text;
1144 
1145                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1146                             (attr->value_tag == IPP_TAG_NAMELANG ||
1147                              attr->value_tag == IPP_TAG_NAME))
1148                                 user_name = attr->values[0].string.text;
1149 
1150                         attr = attr->next;
1151                 }
1152 
1153                /*
1154                 * See if we have everything needed...
1155                 */
1156 
1157                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1158                         if (attr == NULL)
1159                                 break;
1160                         else
1161                                 continue;
1162                 }
1163 
1164                 temp->job      = job_id;
1165                 temp->size     = job_k_octets * 1024;
1166                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1167                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1168                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1169                                  LPQ_PRINTING;
1170                 temp->priority = job_priority;
1171                 temp->time     = job_time;
1172                 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
1173                 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
1174 
1175                 qcount ++;
1176 
1177                 if (attr == NULL)
1178                         break;
1179         }
1180 
1181        /*
1182         * Return the job queue...
1183         */
1184 
1185         *q = queue;
1186 
1187  out:
1188         if (response)
1189                 ippDelete(response);
1190 
1191         if (language)
1192                 cupsLangFree(language);
1193 
1194         if (http)
1195                 httpClose(http);
1196 
1197         return qcount;
1198 }
1199 
1200 
1201 /*
1202  * 'iprint_queue_pause()' - Pause a print queue.
1203  */
1204 
1205 static int iprint_queue_pause(int snum)
     /* [<][>][^][v][top][bottom][index][help] */
1206 {
1207         return(-1); /* Not supported without credentials */
1208 }
1209 
1210 
1211 /*
1212  * 'iprint_queue_resume()' - Restart a print queue.
1213  */
1214 
1215 static int iprint_queue_resume(int snum)
     /* [<][>][^][v][top][bottom][index][help] */
1216 {
1217         return(-1); /* Not supported without credentials */
1218 }
1219 
1220 /*******************************************************************
1221  * iPrint printing interface definitions...
1222  ******************************************************************/
1223 
1224 struct printif  iprint_printif =
1225 {
1226         PRINT_IPRINT,
1227         iprint_queue_get,
1228         iprint_queue_pause,
1229         iprint_queue_resume,
1230         iprint_job_delete,
1231         iprint_job_pause,
1232         iprint_job_resume,
1233         iprint_job_submit,
1234 };
1235 
1236 #else
1237  /* this keeps fussy compilers happy */
1238  void print_iprint_dummy(void);
1239  void print_iprint_dummy(void) {}
     /* [<][>][^][v][top][bottom][index][help] */
1240 #endif /* HAVE_IPRINT */

/* [<][>][^][v][top][bottom][index][help] */